2017-07-21 18:21:34 +02:00
|
|
|
|
/******************************************************************************
|
2018-02-06 14:55:35 +01:00
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
2017-07-21 18:21:34 +02:00
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
#include "QskVirtualKeyboard.h"
|
2018-04-01 12:47:44 +02:00
|
|
|
|
#include "QskTextOptions.h"
|
|
|
|
|
#include "QskLinearBox.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
|
|
#include <QGuiApplication>
|
|
|
|
|
#include <QStyleHints>
|
|
|
|
|
|
2018-04-03 20:15:20 +02:00
|
|
|
|
QSK_QT_PRIVATE_BEGIN
|
2018-04-05 14:18:15 +02:00
|
|
|
|
#include <private/qinputmethod_p.h>
|
2018-04-03 20:15:20 +02:00
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
|
|
|
|
|
#include <qpa/qplatformintegration.h>
|
|
|
|
|
#include <qpa/qplatforminputcontext.h>
|
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
struct KeyTable
|
|
|
|
|
{
|
2018-03-28 09:01:25 -07:00
|
|
|
|
using Row = QskVirtualKeyboard::KeyData[ QskVirtualKeyboard::KeyCount ];
|
|
|
|
|
Row data[ QskVirtualKeyboard::RowCount ];
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
int indexOf( const QskVirtualKeyboard::KeyData* value ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
return int( intptr_t( value - data[0] ) );
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
struct QskVirtualKeyboardLayouts
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
struct KeyCodes
|
|
|
|
|
{
|
2018-03-28 09:01:25 -07:00
|
|
|
|
using Row = Qt::Key[ QskVirtualKeyboard::KeyCount ];
|
|
|
|
|
Row data[ QskVirtualKeyboard::RowCount ];
|
2017-07-21 18:21:34 +02:00
|
|
|
|
};
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
using Layout = KeyCodes[ QskVirtualKeyboard::ModeCount ];
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
|
|
Layout bg; // Bulgarian
|
|
|
|
|
Layout cs; // Czech
|
|
|
|
|
Layout de; // German
|
|
|
|
|
Layout da; // Danish
|
|
|
|
|
Layout el; // Greek
|
|
|
|
|
Layout en_GB; // English (GB)
|
|
|
|
|
Layout en_US; // English (US)
|
|
|
|
|
Layout es; // Spanish
|
|
|
|
|
Layout fi; // Finnish
|
|
|
|
|
Layout fr; // French
|
|
|
|
|
Layout hu; // Hungarian
|
|
|
|
|
Layout it; // Italian
|
|
|
|
|
Layout ja; // Japanese
|
|
|
|
|
Layout lv; // Latvian
|
|
|
|
|
Layout lt; // Lithuanian
|
|
|
|
|
Layout nl; // Dutch
|
|
|
|
|
Layout pt; // Portuguese
|
|
|
|
|
Layout ro; // Romanian
|
|
|
|
|
Layout ru; // Russian
|
|
|
|
|
Layout sl; // Slovene
|
|
|
|
|
Layout sk; // Slovak
|
|
|
|
|
Layout tr; // Turkish
|
|
|
|
|
Layout zh; // Chinese
|
|
|
|
|
|
|
|
|
|
Q_GADGET
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#define LOWER(x) Qt::Key(x + 32) // Convert an uppercase key to lowercase
|
2018-03-28 09:01:25 -07:00
|
|
|
|
static constexpr const QskVirtualKeyboardLayouts qskKeyboardLayouts =
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-03-28 09:01:25 -07:00
|
|
|
|
#include "QskVirtualKeyboardLayouts.cpp"
|
2017-07-21 18:21:34 +02:00
|
|
|
|
};
|
|
|
|
|
#undef LOWER
|
|
|
|
|
|
|
|
|
|
QSK_DECLARE_OPERATORS_FOR_FLAGS( Qt::Key ) // Must appear after the LOWER macro
|
|
|
|
|
|
2018-03-28 11:46:31 +02:00
|
|
|
|
static const int KeyLocked = static_cast< int >( Qt::ControlModifier );
|
|
|
|
|
static const int KeyStates = static_cast< int >( Qt::KeyboardModifierMask );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
|
|
static qreal qskKeyStretch( Qt::Key key )
|
|
|
|
|
{
|
2018-03-14 17:30:35 +01:00
|
|
|
|
switch( key )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
case Qt::Key_Backspace:
|
|
|
|
|
case Qt::Key_Shift:
|
|
|
|
|
case Qt::Key_CapsLock:
|
|
|
|
|
return 1.5;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Space:
|
|
|
|
|
return 3.5;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Return:
|
|
|
|
|
case Qt::Key_Mode_switch:
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
// Possibly smaller
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
return 1.0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
static qreal qskRowStretch( const QskVirtualKeyboard::KeyRow& keyRow )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
qreal stretch = 0;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2018-03-14 17:30:35 +01:00
|
|
|
|
for( const auto& key : keyRow )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-03-14 17:30:35 +01:00
|
|
|
|
if( !key )
|
|
|
|
|
{
|
2017-07-21 18:21:34 +02:00
|
|
|
|
continue;
|
2018-03-14 17:30:35 +01:00
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
|
|
stretch += qskKeyStretch( key );
|
|
|
|
|
}
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2018-03-14 17:30:35 +01:00
|
|
|
|
if( stretch == 0.0 )
|
|
|
|
|
{
|
2018-03-28 09:01:25 -07:00
|
|
|
|
stretch = QskVirtualKeyboard::KeyCount;
|
2018-03-14 17:30:35 +01:00
|
|
|
|
}
|
2017-12-08 13:56:35 +01:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
return stretch;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 11:46:31 +02:00
|
|
|
|
static bool qskIsAutorepeat( int key )
|
2018-03-26 10:05:44 +02:00
|
|
|
|
{
|
|
|
|
|
return ( key != Qt::Key_Return && key != Qt::Key_Enter
|
2018-04-01 12:47:44 +02:00
|
|
|
|
&& key != Qt::Key_Shift && key != Qt::Key_CapsLock
|
|
|
|
|
&& key != Qt::Key_Mode_switch );
|
2017-10-17 17:34:00 +02:00
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
2018-04-04 10:15:59 +02:00
|
|
|
|
static inline QPlatformInputContext* qskInputContext()
|
|
|
|
|
{
|
2018-04-05 14:18:15 +02:00
|
|
|
|
auto inputMethod = QGuiApplication::inputMethod();
|
|
|
|
|
return QInputMethodPrivate::get( inputMethod )->platformInputContext();
|
2018-04-04 10:15:59 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-30 01:15:05 -07:00
|
|
|
|
QSK_SUBCONTROL( QskVirtualKeyboardCandidateButton, Panel )
|
|
|
|
|
QSK_SUBCONTROL( QskVirtualKeyboardCandidateButton, Text )
|
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
QskVirtualKeyboardCandidateButton::QskVirtualKeyboardCandidateButton(
|
|
|
|
|
QskVirtualKeyboard* inputPanel, QQuickItem* parent ) :
|
2018-03-30 01:15:05 -07:00
|
|
|
|
Inherited( parent ),
|
|
|
|
|
m_inputPanel( inputPanel ),
|
|
|
|
|
m_index( -1 )
|
|
|
|
|
{
|
|
|
|
|
setFlag( QQuickItem::ItemAcceptsInputMethod );
|
|
|
|
|
setText( QStringLiteral( " " ) ); // ###
|
|
|
|
|
|
2018-04-03 20:15:20 +02:00
|
|
|
|
connect( this, &QskVirtualKeyboardButton::pressed,
|
|
|
|
|
this, [ this ]() { m_inputPanel->handleCandidateKey( m_index, m_text ); } );
|
2018-03-30 01:15:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QskVirtualKeyboardCandidateButton::setIndexAndText(int index, const QString& text )
|
|
|
|
|
{
|
|
|
|
|
m_index = index;
|
|
|
|
|
m_text = text;
|
|
|
|
|
setText( m_text );
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-03 20:15:20 +02:00
|
|
|
|
QskAspect::Subcontrol QskVirtualKeyboardCandidateButton::effectiveSubcontrol(
|
|
|
|
|
QskAspect::Subcontrol subControl ) const
|
2018-03-30 01:15:05 -07:00
|
|
|
|
{
|
|
|
|
|
if( subControl == QskPushButton::Panel )
|
|
|
|
|
{
|
|
|
|
|
return QskVirtualKeyboardCandidateButton::Panel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( subControl == QskPushButton::Text )
|
|
|
|
|
{
|
|
|
|
|
return QskVirtualKeyboardCandidateButton::Text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return subControl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int QskVirtualKeyboardCandidateButton::maxCandidates()
|
|
|
|
|
{
|
|
|
|
|
return 12;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QSK_SUBCONTROL( QskVirtualKeyboard, Panel )
|
2018-03-15 10:31:50 +01:00
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QSK_SUBCONTROL( QskVirtualKeyboardButton, Panel )
|
|
|
|
|
QSK_SUBCONTROL( QskVirtualKeyboardButton, Text )
|
2018-03-14 17:30:37 +01:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
QskVirtualKeyboardButton::QskVirtualKeyboardButton(
|
|
|
|
|
int keyIndex, QskVirtualKeyboard* inputPanel, QQuickItem* parent ) :
|
2018-03-14 17:30:37 +01:00
|
|
|
|
Inherited( parent ),
|
|
|
|
|
m_keyIndex( keyIndex ),
|
|
|
|
|
m_inputPanel( inputPanel )
|
|
|
|
|
{
|
2018-03-23 07:59:26 +01:00
|
|
|
|
QskTextOptions options;
|
|
|
|
|
options.setFontSizeMode( QskTextOptions::VerticalFit );
|
|
|
|
|
setTextOptions( options );
|
|
|
|
|
|
2018-03-27 19:00:43 +02:00
|
|
|
|
setFocusPolicy( Qt::TabFocus );
|
|
|
|
|
|
2018-03-26 10:05:44 +02:00
|
|
|
|
auto keyData = m_inputPanel->keyDataAt( m_keyIndex );
|
|
|
|
|
const auto key = keyData.key & ~KeyStates;
|
|
|
|
|
|
|
|
|
|
if ( qskIsAutorepeat( key ) )
|
|
|
|
|
{
|
|
|
|
|
setAutoRepeat( true );
|
|
|
|
|
setAutoRepeatDelay( 500 );
|
|
|
|
|
setAutoRepeatInterval( 1000 / QGuiApplication::styleHints()->keyboardAutoRepeatRate() );
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-14 17:30:37 +01:00
|
|
|
|
updateText();
|
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
connect( this, &QskVirtualKeyboardButton::pressed, this,
|
|
|
|
|
[ this ]() { m_inputPanel->handleKey( m_keyIndex ); } );
|
2018-03-14 17:30:37 +01:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
connect( m_inputPanel, &QskVirtualKeyboard::modeChanged,
|
|
|
|
|
this, &QskVirtualKeyboardButton::updateText );
|
2018-03-14 17:30:37 +01:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
QskAspect::Subcontrol QskVirtualKeyboardButton::effectiveSubcontrol(
|
|
|
|
|
QskAspect::Subcontrol subControl ) const
|
2018-03-14 17:30:37 +01:00
|
|
|
|
{
|
|
|
|
|
if( subControl == QskPushButton::Panel )
|
2018-03-28 09:01:25 -07:00
|
|
|
|
return QskVirtualKeyboardButton::Panel;
|
2018-03-14 17:30:37 +01:00
|
|
|
|
|
|
|
|
|
if( subControl == QskPushButton::Text )
|
2018-04-02 17:01:04 +02:00
|
|
|
|
return QskVirtualKeyboardButton::Text;
|
2018-03-14 17:30:37 +01:00
|
|
|
|
|
|
|
|
|
return subControl;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
int QskVirtualKeyboardButton::keyIndex() const
|
2018-03-21 13:00:24 +01:00
|
|
|
|
{
|
|
|
|
|
return m_keyIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
void QskVirtualKeyboardButton::updateText()
|
2018-03-14 17:30:37 +01:00
|
|
|
|
{
|
|
|
|
|
QString text = m_inputPanel->currentTextForKeyIndex( m_keyIndex );
|
|
|
|
|
|
2018-03-28 10:26:33 +02:00
|
|
|
|
if( text.count() == 1 && text.at( 0 ) == QChar( 0 ) )
|
2018-03-14 17:30:37 +01:00
|
|
|
|
{
|
2018-03-28 10:26:33 +02:00
|
|
|
|
setVisible( false );
|
2018-03-14 17:30:37 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-03-28 10:26:33 +02:00
|
|
|
|
setVisible( true );
|
2018-03-14 17:30:37 +01:00
|
|
|
|
setText( text );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
class QskVirtualKeyboard::PrivateData
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
public:
|
|
|
|
|
PrivateData():
|
|
|
|
|
currentLayout( nullptr ),
|
|
|
|
|
mode( QskVirtualKeyboard::LowercaseMode ),
|
|
|
|
|
selectedGroup( -1 ),
|
|
|
|
|
candidateOffset( 0 ),
|
|
|
|
|
candidateBox( nullptr ),
|
|
|
|
|
buttonsBox( nullptr ),
|
|
|
|
|
isUIInitialized( false ),
|
|
|
|
|
candidateBoxVisible( false )
|
|
|
|
|
{
|
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
public:
|
|
|
|
|
const QskVirtualKeyboardLayouts::Layout* currentLayout;
|
|
|
|
|
QskVirtualKeyboard::Mode mode;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
qint16 selectedGroup;
|
|
|
|
|
qint32 candidateOffset;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
QVector< QString > candidates;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
KeyTable keyTable[ ModeCount ];
|
2018-03-14 17:30:37 +01:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
QList< QskVirtualKeyboardCandidateButton* > candidateButtons;
|
|
|
|
|
QskLinearBox* candidateBox;
|
|
|
|
|
QskLinearBox* buttonsBox;
|
|
|
|
|
QList< QskVirtualKeyboardButton* > keyButtons;
|
|
|
|
|
bool isUIInitialized;
|
|
|
|
|
bool candidateBoxVisible;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
};
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QskVirtualKeyboard::QskVirtualKeyboard( QQuickItem* parent ):
|
2018-03-28 15:31:44 +02:00
|
|
|
|
Inherited( parent ),
|
2017-07-21 18:21:34 +02:00
|
|
|
|
m_data( new PrivateData )
|
|
|
|
|
{
|
2018-03-14 17:30:37 +01:00
|
|
|
|
qRegisterMetaType< Qt::Key >();
|
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
setFlag( ItemHasContents );
|
2018-04-06 09:00:09 +02:00
|
|
|
|
setFlag( ItemIsFocusScope, true );
|
|
|
|
|
#if 0
|
|
|
|
|
// TODO ...
|
|
|
|
|
setTabFence( true );
|
|
|
|
|
#endif
|
2017-08-31 09:09:05 +02:00
|
|
|
|
|
|
|
|
|
initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding );
|
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
updateLocale( locale() );
|
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
connect( this, &QskControl::localeChanged,
|
|
|
|
|
this, &QskVirtualKeyboard::updateLocale );
|
2018-03-14 17:30:39 +01:00
|
|
|
|
|
2018-03-22 18:30:15 +01:00
|
|
|
|
setAutoLayoutChildren( true );
|
|
|
|
|
|
|
|
|
|
m_data->buttonsBox = new QskLinearBox( Qt::Vertical, this );
|
|
|
|
|
m_data->buttonsBox->setAutoAddChildren( true );
|
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
const auto& panelKeyData = keyData();
|
|
|
|
|
|
2018-03-22 18:30:15 +01:00
|
|
|
|
for( const auto& keyRow : panelKeyData )
|
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
auto rowBox = new QskLinearBox( Qt::Horizontal, m_data->buttonsBox );
|
2018-03-22 18:30:15 +01:00
|
|
|
|
rowBox->setAutoAddChildren( true );
|
|
|
|
|
|
|
|
|
|
for( const auto& keyData : keyRow )
|
|
|
|
|
{
|
|
|
|
|
if( !keyData.key )
|
|
|
|
|
continue;
|
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
const int keyIndex = m_data->keyTable[ m_data->mode ].indexOf( &keyData );
|
|
|
|
|
|
|
|
|
|
auto button = new QskVirtualKeyboardButton( keyIndex, this, rowBox );
|
2018-04-03 20:15:20 +02:00
|
|
|
|
button->installEventFilter( this );
|
2018-03-28 10:26:33 +02:00
|
|
|
|
rowBox->setRetainSizeWhenHidden( button, true );
|
2018-03-22 18:30:15 +01:00
|
|
|
|
|
|
|
|
|
m_data->keyButtons.append( button );
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QskVirtualKeyboard::~QskVirtualKeyboard()
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
QskAspect::Subcontrol QskVirtualKeyboard::effectiveSubcontrol(
|
|
|
|
|
QskAspect::Subcontrol subControl ) const
|
2018-03-22 15:48:29 +01:00
|
|
|
|
{
|
2018-03-28 15:31:44 +02:00
|
|
|
|
if( subControl == QskBox::Panel )
|
2018-03-28 09:01:25 -07:00
|
|
|
|
return QskVirtualKeyboard::Panel;
|
2018-03-22 15:48:29 +01:00
|
|
|
|
|
|
|
|
|
return subControl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QskVirtualKeyboard::Mode QskVirtualKeyboard::mode() const
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
return m_data->mode;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
const QskVirtualKeyboard::KeyDataSet& QskVirtualKeyboard::keyData( Mode mode ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
mode = mode == CurrentMode ? m_data->mode : mode;
|
|
|
|
|
Q_ASSERT( mode >= 0 && mode < ModeCount );
|
|
|
|
|
return m_data->keyTable[ mode ].data;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QString QskVirtualKeyboard::textForKey( int key ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
key &= ~KeyStates;
|
|
|
|
|
|
|
|
|
|
// Special cases
|
2018-03-14 17:30:35 +01:00
|
|
|
|
switch( key )
|
2017-10-17 19:02:02 +02:00
|
|
|
|
{
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Backspace:
|
|
|
|
|
case Qt::Key_Muhenkan:
|
|
|
|
|
return QChar( 0x232B );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_CapsLock:
|
|
|
|
|
case Qt::Key_Kana_Lock:
|
|
|
|
|
return QChar( 0x21E7 );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Shift:
|
|
|
|
|
case Qt::Key_Kana_Shift:
|
|
|
|
|
return QChar( 0x2B06 );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Mode_switch:
|
|
|
|
|
return QChar( 0x2026 );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Return:
|
|
|
|
|
case Qt::Key_Kanji:
|
|
|
|
|
return QChar( 0x23CE );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Left:
|
|
|
|
|
return QChar( 0x2190 );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Right:
|
|
|
|
|
return QChar( 0x2192 );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_ApplicationLeft:
|
|
|
|
|
return QChar( 0x2B05 );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_ApplicationRight:
|
|
|
|
|
return QChar( 0x27A1 );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: possibly route through locale for custom strings
|
|
|
|
|
|
|
|
|
|
// Default to direct key mapping
|
|
|
|
|
return QChar( key );
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QString QskVirtualKeyboard::displayLanguageName() const
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
const auto locale = this->locale();
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2018-03-14 17:30:35 +01:00
|
|
|
|
switch( locale.language() )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
case QLocale::Bulgarian:
|
|
|
|
|
return QStringLiteral( "български език" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Czech:
|
|
|
|
|
return QStringLiteral( "Čeština" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::German:
|
|
|
|
|
return QStringLiteral( "Deutsch" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Danish:
|
|
|
|
|
return QStringLiteral( "Dansk" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Greek:
|
|
|
|
|
return QStringLiteral( "Eλληνικά" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::English:
|
2018-04-01 12:47:44 +02:00
|
|
|
|
{
|
|
|
|
|
switch( locale.country() )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
case QLocale::Canada:
|
|
|
|
|
case QLocale::UnitedStates:
|
|
|
|
|
case QLocale::UnitedStatesMinorOutlyingIslands:
|
|
|
|
|
case QLocale::UnitedStatesVirginIslands:
|
|
|
|
|
return QStringLiteral( "English (US)" );
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return QStringLiteral( "English (UK)" );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Spanish:
|
|
|
|
|
return QStringLiteral( "Español" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Finnish:
|
|
|
|
|
return QStringLiteral( "Suomi" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::French:
|
|
|
|
|
return QStringLiteral( "Français" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Hungarian:
|
|
|
|
|
return QStringLiteral( "Magyar" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Italian:
|
|
|
|
|
return QStringLiteral( "Italiano" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Japanese:
|
|
|
|
|
return QStringLiteral( "日本語" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Latvian:
|
|
|
|
|
return QStringLiteral( "Latviešu" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Lithuanian:
|
|
|
|
|
return QStringLiteral( "Lietuvių" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Dutch:
|
|
|
|
|
return QStringLiteral( "Nederlands" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Portuguese:
|
|
|
|
|
return QStringLiteral( "Português" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Romanian:
|
|
|
|
|
return QStringLiteral( "Română" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Russia:
|
|
|
|
|
return QStringLiteral( "Русский" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Slovenian:
|
|
|
|
|
return QStringLiteral( "Slovenščina" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Slovak:
|
|
|
|
|
return QStringLiteral( "Slovenčina" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Turkish:
|
|
|
|
|
return QStringLiteral( "Türkçe" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Chinese:
|
|
|
|
|
return QStringLiteral( "中文" );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
return QLocale::languageToString( locale.language() );
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-30 01:15:05 -07:00
|
|
|
|
void QskVirtualKeyboard::setPreeditCandidates( const QVector< QString >& candidates )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-04-05 14:18:15 +02:00
|
|
|
|
if( m_data->candidates != candidates )
|
2018-03-14 17:30:35 +01:00
|
|
|
|
{
|
2018-04-05 14:18:15 +02:00
|
|
|
|
m_data->candidates = candidates;
|
|
|
|
|
setCandidateOffset( 0 );
|
2018-03-14 17:30:35 +01:00
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
void QskVirtualKeyboard::setCandidateOffset( int candidateOffset )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
m_data->candidateOffset = candidateOffset;
|
|
|
|
|
|
|
|
|
|
const auto candidateCount = m_data->candidates.length();
|
2018-03-30 01:15:05 -07:00
|
|
|
|
const auto count = std::min( candidateCount, QskVirtualKeyboardCandidateButton::maxCandidates() );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
const bool continueLeft = m_data->candidateOffset > 0;
|
|
|
|
|
const bool continueRight = ( candidateCount - m_data->candidateOffset ) > count;
|
|
|
|
|
|
2018-03-14 17:30:35 +01:00
|
|
|
|
for( int i = 0; i < count; ++i )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
auto button = m_data->candidateButtons[i];
|
|
|
|
|
|
2018-03-14 17:30:35 +01:00
|
|
|
|
if( continueLeft && i == 0 )
|
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
button->setIndexAndText( i, textForKey( Qt::Key_ApplicationLeft ) );
|
2018-03-14 17:30:35 +01:00
|
|
|
|
}
|
2018-04-04 20:19:47 +02:00
|
|
|
|
else if( continueRight && ( i == KeyCount - 1 ) )
|
2018-03-14 17:30:35 +01:00
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
button->setIndexAndText( i, textForKey( Qt::Key_ApplicationRight ) );
|
2018-03-14 17:30:35 +01:00
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
else
|
2018-03-14 17:30:35 +01:00
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
const int index = i + m_data->candidateOffset;
|
|
|
|
|
button->setIndexAndText( index, m_data->candidates[index] );
|
2018-03-14 17:30:35 +01:00
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-30 01:15:05 -07:00
|
|
|
|
for( int i = count; i < QskVirtualKeyboardCandidateButton::maxCandidates(); ++i )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
m_data->candidateButtons[i]->setIndexAndText( -1, QString() );
|
2018-03-14 17:30:35 +01:00
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
void QskVirtualKeyboard::updateLayout()
|
2018-03-21 13:00:24 +01:00
|
|
|
|
{
|
2018-03-22 18:30:15 +01:00
|
|
|
|
if( geometry().isNull() )
|
|
|
|
|
return; // no need to calculate anything, will be called again
|
2018-03-21 13:00:24 +01:00
|
|
|
|
|
2018-03-28 15:49:45 +02:00
|
|
|
|
QRectF rect = layoutRect();
|
2018-03-21 13:00:24 +01:00
|
|
|
|
qreal verticalSpacing = m_data->buttonsBox->spacing();
|
|
|
|
|
|
2018-03-28 15:49:45 +02:00
|
|
|
|
const auto& children = m_data->buttonsBox->childItems();
|
|
|
|
|
for( auto rowItem : children )
|
2018-03-21 13:00:24 +01:00
|
|
|
|
{
|
2018-03-28 15:49:45 +02:00
|
|
|
|
auto rowBox = qobject_cast< QskLinearBox* >( rowItem );
|
|
|
|
|
const qreal horizontalSpacing = rowBox->spacing();
|
2018-03-21 13:00:24 +01:00
|
|
|
|
|
2018-03-28 15:49:45 +02:00
|
|
|
|
const auto& rowChildren = rowBox->childItems();
|
|
|
|
|
for( auto keyItem : rowChildren )
|
2018-03-21 13:00:24 +01:00
|
|
|
|
{
|
2018-03-28 09:01:25 -07:00
|
|
|
|
auto button = qobject_cast< QskVirtualKeyboardButton* >( keyItem );
|
2018-03-21 13:00:24 +01:00
|
|
|
|
QRectF keyRect = keyDataAt( button->keyIndex() ).rect;
|
|
|
|
|
qreal width = keyRect.width() * rect.width() - horizontalSpacing;
|
|
|
|
|
qreal height = keyRect.height() * rect.height() - verticalSpacing;
|
|
|
|
|
|
|
|
|
|
button->setFixedSize( width, height );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-30 01:15:05 -07:00
|
|
|
|
void QskVirtualKeyboard::createUI()
|
|
|
|
|
{
|
|
|
|
|
setAutoLayoutChildren( true );
|
|
|
|
|
|
2018-03-30 15:04:26 +02:00
|
|
|
|
auto outerBox = new QskLinearBox( Qt::Vertical, this );
|
2018-03-30 01:15:05 -07:00
|
|
|
|
|
2018-03-30 15:04:26 +02:00
|
|
|
|
m_data->candidateBox = new QskLinearBox( Qt::Horizontal, outerBox );
|
|
|
|
|
#if 1
|
|
|
|
|
// should be skin hints TODO ...
|
2018-03-30 01:15:05 -07:00
|
|
|
|
QMarginsF margins( 0, 10, 0, 20 ); // ###
|
|
|
|
|
m_data->candidateBox->setMargins( margins );
|
2018-03-30 15:04:26 +02:00
|
|
|
|
#endif
|
2018-03-30 01:15:05 -07:00
|
|
|
|
|
|
|
|
|
// to determine suggestions buttons width
|
|
|
|
|
// (otherwise empty buttons would be too small when there are only a few suggestions):
|
|
|
|
|
// ### Can this be done with the layout engine or so?
|
|
|
|
|
QRectF rect = layoutRect();
|
|
|
|
|
auto candidateButtonWidth = rect.width() / QskVirtualKeyboardCandidateButton::maxCandidates()
|
2018-04-01 12:47:44 +02:00
|
|
|
|
- m_data->candidateBox->spacing() * QskVirtualKeyboardCandidateButton::maxCandidates();
|
2018-03-30 01:15:05 -07:00
|
|
|
|
|
|
|
|
|
for( int a = 0; a < QskVirtualKeyboardCandidateButton::maxCandidates(); ++a )
|
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
auto button = new QskVirtualKeyboardCandidateButton( this, m_data->candidateBox );
|
|
|
|
|
|
|
|
|
|
qreal height = button->sizeHint().height();
|
2018-03-30 15:04:26 +02:00
|
|
|
|
#if 1
|
2018-04-01 12:47:44 +02:00
|
|
|
|
// should be done by margins/paddings
|
|
|
|
|
button->setPreferredHeight( height + 10 );
|
2018-03-30 15:04:26 +02:00
|
|
|
|
#endif
|
2018-04-01 12:47:44 +02:00
|
|
|
|
button->setPreferredWidth( candidateButtonWidth );
|
|
|
|
|
button->installEventFilter( this );
|
2018-03-30 01:15:05 -07:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
m_data->candidateBox->setRetainSizeWhenHidden( button, true );
|
|
|
|
|
m_data->candidateButtons.append( button );
|
2018-03-30 01:15:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_data->candidateBox->setVisible( m_data->candidateBoxVisible );
|
2018-03-30 15:04:26 +02:00
|
|
|
|
outerBox->setRetainSizeWhenHidden( m_data->candidateBox, true );
|
2018-03-30 01:15:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
void QskVirtualKeyboard::updateUI()
|
2018-03-14 17:30:37 +01:00
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
for( auto button : qskAsConst( m_data->keyButtons ) )
|
2018-03-14 17:30:37 +01:00
|
|
|
|
button->updateText();
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QskVirtualKeyboard::KeyData& QskVirtualKeyboard::keyDataAt( int keyIndex ) const
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
const auto row = keyIndex / KeyCount;
|
|
|
|
|
const auto col = keyIndex % KeyCount;
|
2018-04-01 12:47:44 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
return m_data->keyTable[ m_data->mode ].data[ row ][ col ];
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
void QskVirtualKeyboard::handleKey( int keyIndex )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-03-14 17:30:37 +01:00
|
|
|
|
KeyData keyData = keyDataAt( keyIndex );
|
|
|
|
|
const auto key = keyData.key & ~KeyStates;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
|
|
// Mode-switching keys
|
2018-03-14 17:30:35 +01:00
|
|
|
|
switch( key )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
case Qt::Key_CapsLock:
|
|
|
|
|
case Qt::Key_Kana_Lock:
|
2018-04-06 09:00:09 +02:00
|
|
|
|
{
|
2017-07-21 18:21:34 +02:00
|
|
|
|
setMode( UppercaseMode ); // Lock caps
|
2018-04-06 09:00:09 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Shift:
|
|
|
|
|
case Qt::Key_Kana_Shift:
|
2018-04-06 09:00:09 +02:00
|
|
|
|
{
|
2017-07-21 18:21:34 +02:00
|
|
|
|
setMode( LowercaseMode ); // Unlock caps
|
2018-04-06 09:00:09 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case Qt::Key_Mode_switch: // Cycle through modes, but skip caps
|
2018-04-06 09:00:09 +02:00
|
|
|
|
{
|
2018-03-28 09:01:25 -07:00
|
|
|
|
setMode( static_cast< QskVirtualKeyboard::Mode >(
|
2018-04-01 12:47:44 +02:00
|
|
|
|
m_data->mode ? ( ( m_data->mode + 1 ) % QskVirtualKeyboard::ModeCount )
|
|
|
|
|
: SpecialCharacterMode ) );
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2018-04-06 09:00:09 +02:00
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
2018-04-06 09:00:09 +02:00
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
QGuiApplication::inputMethod()->invokeAction(
|
|
|
|
|
static_cast< QInputMethod::Action >( Compose ), key );
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-03-30 01:15:05 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QskVirtualKeyboard::handleCandidateKey( int index, const QString& text )
|
|
|
|
|
{
|
|
|
|
|
if( text == textForKey( Qt::Key_ApplicationLeft ) )
|
2018-03-14 17:30:37 +01:00
|
|
|
|
{
|
2018-03-30 01:15:05 -07:00
|
|
|
|
setCandidateOffset( m_data->candidateOffset - 1 );
|
|
|
|
|
}
|
|
|
|
|
else if( text == textForKey( Qt::Key_ApplicationRight ) )
|
|
|
|
|
{
|
|
|
|
|
setCandidateOffset( m_data->candidateOffset + 1 );
|
2018-03-14 17:30:37 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-04-06 09:00:09 +02:00
|
|
|
|
QGuiApplication::inputMethod()->invokeAction(
|
|
|
|
|
static_cast< QInputMethod::Action >( SelectCandidate ), index );
|
|
|
|
|
|
2018-04-05 14:18:15 +02:00
|
|
|
|
setPreeditCandidates( QVector< QString >() );
|
2018-03-14 17:30:37 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-30 01:15:05 -07:00
|
|
|
|
void QskVirtualKeyboard::setCandidateBarVisible( bool visible )
|
|
|
|
|
{
|
|
|
|
|
// need to cache it until we have created the UI
|
|
|
|
|
m_data->candidateBoxVisible = visible;
|
|
|
|
|
if( m_data->isUIInitialized )
|
|
|
|
|
m_data->candidateBox->setVisible( m_data->candidateBoxVisible );
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
QString QskVirtualKeyboard::currentTextForKeyIndex( int keyIndex ) const
|
2018-03-14 17:30:37 +01:00
|
|
|
|
{
|
|
|
|
|
auto keyData = keyDataAt( keyIndex );
|
|
|
|
|
QString text = textForKey( keyData.key );
|
|
|
|
|
return text;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
void QskVirtualKeyboard::updateLocale( const QLocale& locale )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-03-14 17:30:35 +01:00
|
|
|
|
switch( locale.language() )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
case QLocale::Bulgarian:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.bg;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Czech:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.cs;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::German:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.de;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Danish:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.da;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Greek:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.el;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::English:
|
2018-04-01 12:47:44 +02:00
|
|
|
|
{
|
|
|
|
|
switch( locale.country() )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
2018-04-01 12:47:44 +02:00
|
|
|
|
case QLocale::Canada:
|
|
|
|
|
case QLocale::UnitedStates:
|
|
|
|
|
case QLocale::UnitedStatesMinorOutlyingIslands:
|
|
|
|
|
case QLocale::UnitedStatesVirginIslands:
|
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.en_US;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.en_GB;
|
|
|
|
|
break;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
2018-03-14 17:30:35 +01:00
|
|
|
|
|
2018-04-01 12:47:44 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Spanish:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.es;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Finnish:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.fi;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::French:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.fr;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Hungarian:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.hu;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Italian:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.it;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Japanese:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.ja;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Latvian:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.lv;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Lithuanian:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.lt;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Dutch:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.nl;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Portuguese:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.pt;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Romanian:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.ro;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Russia:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.ru;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Slovenian:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.sl;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Slovak:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.sk;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Turkish:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.tr;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2017-10-17 19:02:02 +02:00
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
case QLocale::Chinese:
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.zh;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
break;
|
2018-03-28 09:01:25 -07:00
|
|
|
|
#if 1
|
|
|
|
|
case QLocale::C:
|
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.en_US;
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
2017-12-11 08:58:57 +01:00
|
|
|
|
default:
|
|
|
|
|
qWarning() << "QskInputPanel: unsupported locale:" << locale;
|
2018-03-28 09:01:25 -07:00
|
|
|
|
m_data->currentLayout = &qskKeyboardLayouts.en_US;
|
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-17 19:02:02 +02:00
|
|
|
|
Q_EMIT displayLanguageNameChanged();
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
|
|
updateKeyData();
|
|
|
|
|
setMode( LowercaseMode );
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
void QskVirtualKeyboard::updateKeyData()
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
// Key data is in normalized coordinates
|
|
|
|
|
const auto keyHeight = 1.0f / RowCount;
|
|
|
|
|
|
2018-03-14 17:30:35 +01:00
|
|
|
|
for( const auto& keyLayout : *m_data->currentLayout )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
auto& keyDataLayout = m_data->keyTable[ &keyLayout - *m_data->currentLayout ];
|
|
|
|
|
qreal yPos = 0;
|
|
|
|
|
|
2018-03-14 17:30:35 +01:00
|
|
|
|
for( int i = 0; i < RowCount; i++ )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
auto& row = keyLayout.data[i];
|
|
|
|
|
auto& keyDataRow = keyDataLayout.data[ i ];
|
|
|
|
|
|
2017-12-07 17:12:52 +01:00
|
|
|
|
const auto baseKeyWidth = 1.0 / qskRowStretch( row );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
|
|
qreal xPos = 0;
|
|
|
|
|
qreal keyWidth = baseKeyWidth;
|
|
|
|
|
|
2018-03-14 17:30:35 +01:00
|
|
|
|
for( const auto& key : row )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
auto& keyData = keyDataRow[ &key - row ];
|
|
|
|
|
keyData.key = key;
|
|
|
|
|
|
|
|
|
|
keyWidth = baseKeyWidth * qskKeyStretch( key );
|
|
|
|
|
keyData.rect = { xPos, yPos, keyWidth, keyHeight };
|
|
|
|
|
xPos += keyWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
yPos += keyHeight;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
void QskVirtualKeyboard::setMode( QskVirtualKeyboard::Mode mode )
|
2017-07-21 18:21:34 +02:00
|
|
|
|
{
|
|
|
|
|
m_data->mode = mode;
|
2018-04-06 09:00:09 +02:00
|
|
|
|
polish();
|
|
|
|
|
|
2018-03-14 17:30:37 +01:00
|
|
|
|
Q_EMIT modeChanged( m_data->mode );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-04-03 20:15:20 +02:00
|
|
|
|
bool QskVirtualKeyboard::eventFilter( QObject* object, QEvent* event )
|
|
|
|
|
{
|
|
|
|
|
if ( event->type() == QEvent::InputMethodQuery )
|
|
|
|
|
{
|
|
|
|
|
/*
|
2018-04-05 14:18:15 +02:00
|
|
|
|
Qt/Quick expects that the item associated with the input context
|
|
|
|
|
always has the focus. But this does not work, when a virtual
|
|
|
|
|
keyboard is used, where you can navigate and select inside.
|
2018-04-03 20:15:20 +02:00
|
|
|
|
So we have to fix the receiver.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-04-04 10:15:59 +02:00
|
|
|
|
if ( const auto inputContext = qskInputContext() )
|
2018-04-03 20:15:20 +02:00
|
|
|
|
{
|
|
|
|
|
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 );
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-28 09:01:25 -07:00
|
|
|
|
#include "moc_QskVirtualKeyboard.cpp"
|