input panel formatting

This commit is contained in:
Peter Hartmann 2018-03-14 17:30:35 +01:00
parent 2f2d5cf122
commit 2e3834acf9
2 changed files with 193 additions and 124 deletions

View File

@ -37,8 +37,10 @@ namespace
QskInputPanel::KeyData* qskKeyDataAt( KeyTable& table, qreal x, qreal y ) QskInputPanel::KeyData* qskKeyDataAt( KeyTable& table, qreal x, qreal y )
{ {
if ( x < 0 || x > 1 || y < 0 || y > 1 ) if( x < 0 || x > 1 || y < 0 || y > 1 )
{
return nullptr; return nullptr;
}
auto rowIndex = size_t( std::floor( y * QskInputPanel::RowCount ) ); auto rowIndex = size_t( std::floor( y * QskInputPanel::RowCount ) );
auto columnIndex = size_t( std::floor( x * QskInputPanel::KeyCount ) ); auto columnIndex = size_t( std::floor( x * QskInputPanel::KeyCount ) );
@ -46,40 +48,51 @@ namespace
Q_FOREVER Q_FOREVER
{ {
const auto rect = table.data[ rowIndex ][ columnIndex ].rect; const auto rect = table.data[ rowIndex ][ columnIndex ].rect;
if ( rect.contains( x, y ) )
if( rect.contains( x, y ) )
{
return &table.data[ rowIndex ][ columnIndex ]; return &table.data[ rowIndex ][ columnIndex ];
}
// Look up/down // Look up/down
if ( y < rect.top() ) if( y < rect.top() )
{ {
if ( rowIndex == 0 ) if( rowIndex == 0 )
{
break; break;
}
rowIndex -= 1; rowIndex -= 1;
continue; continue;
} }
else if ( y > rect.bottom() ) else if( y > rect.bottom() )
{ {
if ( rowIndex == QskInputPanel::RowCount - 1 ) if( rowIndex == QskInputPanel::RowCount - 1 )
{
break; break;
}
rowIndex += 1; rowIndex += 1;
continue; continue;
} }
// Look left/right // Look left/right
if ( x < rect.left() ) if( x < rect.left() )
{ {
if ( columnIndex == 0 ) if( columnIndex == 0 )
{
break; break;
}
columnIndex -= 1; columnIndex -= 1;
continue; continue;
} }
else if ( x > rect.right() ) else if( x > rect.right() )
{ {
if ( columnIndex == QskInputPanel::KeyCount - 1 ) if( columnIndex == QskInputPanel::KeyCount - 1 )
{
break; break;
}
columnIndex += 1; columnIndex += 1;
continue; continue;
@ -130,7 +143,7 @@ struct QskInputPanelLayouts
#define LOWER(x) Qt::Key(x + 32) // Convert an uppercase key to lowercase #define LOWER(x) Qt::Key(x + 32) // Convert an uppercase key to lowercase
static constexpr const QskInputPanelLayouts qskInputPanelLayouts = static constexpr const QskInputPanelLayouts qskInputPanelLayouts =
{ {
#include "QskInputPanelLayouts.cpp" #include "QskInputPanelLayouts.cpp"
}; };
#undef LOWER #undef LOWER
@ -143,7 +156,7 @@ static const Qt::Key KeyStates = static_cast< Qt::Key >( Qt::KeyboardModifierMa
static qreal qskKeyStretch( Qt::Key key ) static qreal qskKeyStretch( Qt::Key key )
{ {
switch ( key ) switch( key )
{ {
case Qt::Key_Backspace: case Qt::Key_Backspace:
case Qt::Key_Shift: case Qt::Key_Shift:
@ -168,16 +181,20 @@ static qreal qskRowStretch( const QskInputPanel::KeyRow& keyRow )
{ {
qreal stretch = 0; qreal stretch = 0;
for ( const auto& key : keyRow ) for( const auto& key : keyRow )
{ {
if ( !key ) if( !key )
{
continue; continue;
}
stretch += qskKeyStretch( key ); stretch += qskKeyStretch( key );
} }
if ( stretch == 0.0 ) if( stretch == 0.0 )
{
stretch = QskInputPanel::KeyCount; stretch = QskInputPanel::KeyCount;
}
return stretch; return stretch;
} }
@ -193,34 +210,34 @@ namespace
class QskInputPanel::PrivateData class QskInputPanel::PrivateData
{ {
public: public:
PrivateData(): PrivateData():
currentLayout( nullptr ), currentLayout( nullptr ),
mode( QskInputPanel::LowercaseMode ), mode( QskInputPanel::LowercaseMode ),
focusKeyIndex( -1 ), focusKeyIndex( -1 ),
selectedGroup( -1 ), selectedGroup( -1 ),
candidateOffset( 0 ), candidateOffset( 0 ),
repeatKeyTimerId( -1 ) repeatKeyTimerId( -1 )
{ {
} }
public: public:
const QskInputPanelLayouts::Layout* currentLayout; const QskInputPanelLayouts::Layout* currentLayout;
QskInputPanel::Mode mode; QskInputPanel::Mode mode;
qint16 focusKeyIndex; qint16 focusKeyIndex;
qint16 selectedGroup; qint16 selectedGroup;
qint32 candidateOffset; qint32 candidateOffset;
int repeatKeyTimerId; int repeatKeyTimerId;
QLocale locale; QLocale locale;
QVector< Qt::Key > groups; QVector< Qt::Key > groups;
QVector< Qt::Key > candidates; QVector< Qt::Key > candidates;
std::unordered_map< int, KeyCounter > activeKeys; std::unordered_map< int, KeyCounter > activeKeys;
KeyTable keyTable[ ModeCount ]; KeyTable keyTable[ ModeCount ];
}; };
QskInputPanel::QskInputPanel( QQuickItem* parent ): QskInputPanel::QskInputPanel( QQuickItem* parent ):
@ -235,7 +252,7 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ):
updateLocale( locale() ); updateLocale( locale() );
QObject::connect( this, &QskControl::localeChanged, QObject::connect( this, &QskControl::localeChanged,
this, &QskInputPanel::updateLocale ); this, &QskInputPanel::updateLocale );
} }
QskInputPanel::~QskInputPanel() QskInputPanel::~QskInputPanel()
@ -259,7 +276,7 @@ QString QskInputPanel::textForKey( Qt::Key key ) const
key &= ~KeyStates; key &= ~KeyStates;
// Special cases // Special cases
switch ( key ) switch( key )
{ {
case Qt::Key_Backspace: case Qt::Key_Backspace:
case Qt::Key_Muhenkan: case Qt::Key_Muhenkan:
@ -306,7 +323,7 @@ QString QskInputPanel::displayLanguageName() const
{ {
const auto locale = this->locale(); const auto locale = this->locale();
switch ( locale.language() ) switch( locale.language() )
{ {
case QLocale::Bulgarian: case QLocale::Bulgarian:
return QStringLiteral( "български език" ); return QStringLiteral( "български език" );
@ -324,19 +341,19 @@ QString QskInputPanel::displayLanguageName() const
return QStringLiteral( "Eλληνικά" ); return QStringLiteral( "Eλληνικά" );
case QLocale::English: case QLocale::English:
{
switch ( locale.country() )
{ {
case QLocale::Canada: switch( locale.country() )
case QLocale::UnitedStates: {
case QLocale::UnitedStatesMinorOutlyingIslands: case QLocale::Canada:
case QLocale::UnitedStatesVirginIslands: case QLocale::UnitedStates:
return QStringLiteral( "English (US)" ); case QLocale::UnitedStatesMinorOutlyingIslands:
case QLocale::UnitedStatesVirginIslands:
return QStringLiteral( "English (US)" );
default: default:
return QStringLiteral( "English (UK)" ); return QStringLiteral( "English (UK)" );
}
} }
}
case QLocale::Spanish: case QLocale::Spanish:
return QStringLiteral( "Español" ); return QStringLiteral( "Español" );
@ -397,7 +414,7 @@ void QskInputPanel::setPreeditGroups( const QVector< Qt::Key >& groups )
{ {
auto& topRow = m_data->keyTable[ LowercaseMode ].data[ 0 ]; auto& topRow = m_data->keyTable[ LowercaseMode ].data[ 0 ];
for ( const auto& group : groups ) for( const auto& group : groups )
{ {
auto& keyData = topRow[ &group - groups.data() ]; auto& keyData = topRow[ &group - groups.data() ];
keyData.key = group; keyData.key = group;
@ -406,14 +423,18 @@ void QskInputPanel::setPreeditGroups( const QVector< Qt::Key >& groups )
m_data->groups = groups; m_data->groups = groups;
selectGroup( -1 ); selectGroup( -1 );
if ( m_data->mode == LowercaseMode ) if( m_data->mode == LowercaseMode )
{
update(); update();
}
} }
void QskInputPanel::setPreeditCandidates( const QVector< Qt::Key >& candidates ) void QskInputPanel::setPreeditCandidates( const QVector< Qt::Key >& candidates )
{ {
if ( m_data->candidates == candidates ) if( m_data->candidates == candidates )
{
return; return;
}
m_data->candidates = candidates; m_data->candidates = candidates;
setCandidateOffset( 0 ); setCandidateOffset( 0 );
@ -429,19 +450,25 @@ bool QskInputPanel::advanceFocus( bool forward )
Q_FOREVER Q_FOREVER
{ {
focusKeyIndex += offset; focusKeyIndex += offset;
if ( focusKeyIndex < 0 || focusKeyIndex >= RowCount * KeyCount )
if( focusKeyIndex < 0 || focusKeyIndex >= RowCount * KeyCount )
{ {
clearFocusKey(); clearFocusKey();
return false; return false;
} }
const auto key = keyDataAt( focusKeyIndex ).key; const auto key = keyDataAt( focusKeyIndex ).key;
if ( key && key != Qt::Key_unknown )
if( key && key != Qt::Key_unknown )
{
break; break;
}
} }
if ( m_data->focusKeyIndex >= 0 ) if( m_data->focusKeyIndex >= 0 )
{
keyDataAt( m_data->focusKeyIndex ).key &= ~KeyFocused; keyDataAt( m_data->focusKeyIndex ).key &= ~KeyFocused;
}
m_data->focusKeyIndex = focusKeyIndex; m_data->focusKeyIndex = focusKeyIndex;
keyDataAt( m_data->focusKeyIndex ).key |= KeyFocused; keyDataAt( m_data->focusKeyIndex ).key |= KeyFocused;
@ -451,14 +478,18 @@ bool QskInputPanel::advanceFocus( bool forward )
bool QskInputPanel::activateFocusKey() bool QskInputPanel::activateFocusKey()
{ {
if ( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount )
{ {
auto& keyData = keyDataAt( m_data->focusKeyIndex ); auto& keyData = keyDataAt( m_data->focusKeyIndex );
if ( keyData.key & KeyPressed ) if( keyData.key & KeyPressed )
{
handleKey( m_data->focusKeyIndex ); handleKey( m_data->focusKeyIndex );
}
else else
{
keyData.key |= KeyPressed; keyData.key |= KeyPressed;
}
update(); update();
return true; return true;
@ -469,10 +500,11 @@ bool QskInputPanel::activateFocusKey()
bool QskInputPanel::deactivateFocusKey() bool QskInputPanel::deactivateFocusKey()
{ {
if ( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount )
{ {
auto& keyData = keyDataAt( m_data->focusKeyIndex ); auto& keyData = keyDataAt( m_data->focusKeyIndex );
if ( keyData.key & KeyPressed )
if( keyData.key & KeyPressed )
{ {
keyData.key &= ~KeyPressed; keyData.key &= ~KeyPressed;
handleKey( m_data->focusKeyIndex ); handleKey( m_data->focusKeyIndex );
@ -487,7 +519,7 @@ bool QskInputPanel::deactivateFocusKey()
void QskInputPanel::clearFocusKey() void QskInputPanel::clearFocusKey()
{ {
if ( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount )
{ {
keyDataAt( m_data->focusKeyIndex ).key &= ~KeyFocused; keyDataAt( m_data->focusKeyIndex ).key &= ~KeyFocused;
update(); update();
@ -508,34 +540,44 @@ void QskInputPanel::setCandidateOffset( int candidateOffset )
const bool continueLeft = m_data->candidateOffset > 0; const bool continueLeft = m_data->candidateOffset > 0;
const bool continueRight = ( candidateCount - m_data->candidateOffset ) > count; const bool continueRight = ( candidateCount - m_data->candidateOffset ) > count;
for ( int i = 0; i < count; ++i ) for( int i = 0; i < count; ++i )
{ {
auto& keyData = topRow[ i + groupCount ]; auto& keyData = topRow[ i + groupCount ];
if ( continueLeft && i == 0 ) if( continueLeft && i == 0 )
{
keyData.key = Qt::Key_ApplicationLeft; keyData.key = Qt::Key_ApplicationLeft;
else if ( continueRight && ( i == KeyCount - groupCount - 1 ) ) }
else if( continueRight && ( i == KeyCount - groupCount - 1 ) )
{
keyData.key = Qt::Key_ApplicationRight; keyData.key = Qt::Key_ApplicationRight;
}
else else
{
keyData.key = m_data->candidates.at( i + m_data->candidateOffset ); keyData.key = m_data->candidates.at( i + m_data->candidateOffset );
}
} }
for ( int i = count; i < KeyCount - groupCount; ++i ) for( int i = count; i < KeyCount - groupCount; ++i )
{ {
auto& keyData = topRow[ i + groupCount ]; auto& keyData = topRow[ i + groupCount ];
keyData.key = Qt::Key_unknown; keyData.key = Qt::Key_unknown;
} }
if ( m_data->mode == LowercaseMode ) if( m_data->mode == LowercaseMode )
{
update(); update();
}
} }
QRectF QskInputPanel::keyboardRect() const QRectF QskInputPanel::keyboardRect() const
{ {
auto keyboardRect = rect(); // ### margins? would eliminate this thing below auto keyboardRect = rect(); // ### margins? would eliminate this thing below
if ( QskDialog::instance()->policy() != QskDialog::TopLevelWindow ) if( QskDialog::instance()->policy() != QskDialog::TopLevelWindow )
{
keyboardRect.adjust( 0, keyboardRect.height() * 0.5, 0, 0 ); keyboardRect.adjust( 0, keyboardRect.height() * 0.5, 0, 0 );
}
return keyboardRect; return keyboardRect;
} }
@ -549,7 +591,7 @@ void QskInputPanel::geometryChanged(
void QskInputPanel::mousePressEvent( QMouseEvent* e ) void QskInputPanel::mousePressEvent( QMouseEvent* e )
{ {
if ( !keyboardRect().contains( e->pos() ) ) if( !keyboardRect().contains( e->pos() ) )
{ {
e->ignore(); e->ignore();
return; return;
@ -560,7 +602,7 @@ void QskInputPanel::mousePressEvent( QMouseEvent* e )
touchPoint.setState( Qt::TouchPointPressed ); touchPoint.setState( Qt::TouchPointPressed );
QTouchEvent touchEvent( QTouchEvent::TouchBegin, nullptr, QTouchEvent touchEvent( QTouchEvent::TouchBegin, nullptr,
e->modifiers(), Qt::TouchPointPressed, { touchPoint } ); e->modifiers(), Qt::TouchPointPressed, { touchPoint } );
QCoreApplication::sendEvent( this, &touchEvent ); QCoreApplication::sendEvent( this, &touchEvent );
e->setAccepted( touchEvent.isAccepted() ); e->setAccepted( touchEvent.isAccepted() );
@ -573,7 +615,7 @@ void QskInputPanel::mouseMoveEvent( QMouseEvent* e )
touchPoint.setState( Qt::TouchPointMoved ); touchPoint.setState( Qt::TouchPointMoved );
QTouchEvent touchEvent( QTouchEvent::TouchUpdate, nullptr, QTouchEvent touchEvent( QTouchEvent::TouchUpdate, nullptr,
e->modifiers(), Qt::TouchPointMoved, { touchPoint } ); e->modifiers(), Qt::TouchPointMoved, { touchPoint } );
QCoreApplication::sendEvent( this, &touchEvent ); QCoreApplication::sendEvent( this, &touchEvent );
e->setAccepted( touchEvent.isAccepted() ); e->setAccepted( touchEvent.isAccepted() );
@ -586,7 +628,7 @@ void QskInputPanel::mouseReleaseEvent( QMouseEvent* e )
touchPoint.setState( Qt::TouchPointReleased ); touchPoint.setState( Qt::TouchPointReleased );
QTouchEvent touchEvent( QTouchEvent::TouchEnd, nullptr, QTouchEvent touchEvent( QTouchEvent::TouchEnd, nullptr,
e->modifiers(), Qt::TouchPointReleased, { touchPoint } ); e->modifiers(), Qt::TouchPointReleased, { touchPoint } );
QCoreApplication::sendEvent( this, &touchEvent ); QCoreApplication::sendEvent( this, &touchEvent );
e->setAccepted( touchEvent.isAccepted() ); e->setAccepted( touchEvent.isAccepted() );
@ -595,17 +637,20 @@ void QskInputPanel::mouseReleaseEvent( QMouseEvent* e )
// Try to handle touch-specific details here; once touch is resolved, send to handleKey() // Try to handle touch-specific details here; once touch is resolved, send to handleKey()
void QskInputPanel::touchEvent( QTouchEvent* e ) void QskInputPanel::touchEvent( QTouchEvent* e )
{ {
if ( e->type() == QEvent::TouchCancel ) if( e->type() == QEvent::TouchCancel )
{ {
for ( auto& it : m_data->activeKeys ) for( auto& it : m_data->activeKeys )
{
keyDataAt( it.second.keyIndex ).key &= ~KeyPressed; keyDataAt( it.second.keyIndex ).key &= ~KeyPressed;
}
m_data->activeKeys.clear(); m_data->activeKeys.clear();
return; return;
} }
const auto rect = keyboardRect(); const auto rect = keyboardRect();
for ( const auto& tp : e->touchPoints() )
for( const auto& tp : e->touchPoints() )
{ {
const auto pos = tp.pos(); const auto pos = tp.pos();
@ -613,11 +658,15 @@ void QskInputPanel::touchEvent( QTouchEvent* e )
const auto y = ( pos.y() - rect.y() ) / rect.height(); const auto y = ( pos.y() - rect.y() ) / rect.height();
auto keyData = qskKeyDataAt( m_data->keyTable[ m_data->mode ], x, y ); auto keyData = qskKeyDataAt( m_data->keyTable[ m_data->mode ], x, y );
if ( !keyData || ( !keyData->key || keyData->key == Qt::Key_unknown ) )
if( !keyData || ( !keyData->key || keyData->key == Qt::Key_unknown ) )
{ {
auto it = m_data->activeKeys.find( tp.id() ); auto it = m_data->activeKeys.find( tp.id() );
if ( it == m_data->activeKeys.cend() )
if( it == m_data->activeKeys.cend() )
{
continue; continue;
}
keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; keyDataAt( it->second.keyIndex ).key &= ~KeyPressed;
m_data->activeKeys.erase( it ); m_data->activeKeys.erase( it );
@ -627,7 +676,7 @@ void QskInputPanel::touchEvent( QTouchEvent* e )
const auto keyIndex = m_data->keyTable[ m_data->mode ].indexOf( keyData ); const auto keyIndex = m_data->keyTable[ m_data->mode ].indexOf( keyData );
auto it = m_data->activeKeys.find( tp.id() ); auto it = m_data->activeKeys.find( tp.id() );
if ( tp.state() == Qt::TouchPointReleased ) if( tp.state() == Qt::TouchPointReleased )
{ {
const int repeatCount = it->second.count; const int repeatCount = it->second.count;
@ -635,20 +684,22 @@ void QskInputPanel::touchEvent( QTouchEvent* e )
keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; keyDataAt( it->second.keyIndex ).key &= ~KeyPressed;
m_data->activeKeys.erase( it ); m_data->activeKeys.erase( it );
if ( repeatCount < 0 ) if( repeatCount < 0 )
continue; // Don't compose an accepted held key {
continue; // Don't compose an accepted held key
}
handleKey( keyIndex ); handleKey( keyIndex );
continue; continue;
} }
if ( it == m_data->activeKeys.end() ) if( it == m_data->activeKeys.end() )
{ {
m_data->activeKeys.emplace( tp.id(), KeyCounter { keyIndex, 0 } ); m_data->activeKeys.emplace( tp.id(), KeyCounter { keyIndex, 0 } );
} }
else else
{ {
if ( it->second.keyIndex != keyIndex ) if( it->second.keyIndex != keyIndex )
{ {
keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; keyDataAt( it->second.keyIndex ).key &= ~KeyPressed;
it->second.count = 0; it->second.count = 0;
@ -661,15 +712,15 @@ void QskInputPanel::touchEvent( QTouchEvent* e )
} }
// Now start an update timer based on active keys // Now start an update timer based on active keys
if ( m_data->activeKeys.empty() && m_data->repeatKeyTimerId >= 0 ) if( m_data->activeKeys.empty() && m_data->repeatKeyTimerId >= 0 )
{ {
killTimer( m_data->repeatKeyTimerId ); killTimer( m_data->repeatKeyTimerId );
m_data->repeatKeyTimerId = -1; m_data->repeatKeyTimerId = -1;
} }
else if ( m_data->repeatKeyTimerId < 0 ) else if( m_data->repeatKeyTimerId < 0 )
{ {
m_data->repeatKeyTimerId = startTimer( 1000 m_data->repeatKeyTimerId = startTimer( 1000
/ QGuiApplication::styleHints()->keyboardAutoRepeatRate() ); / QGuiApplication::styleHints()->keyboardAutoRepeatRate() );
} /* else timer is already running as it should be */ } /* else timer is already running as it should be */
update(); update();
@ -677,31 +728,32 @@ void QskInputPanel::touchEvent( QTouchEvent* e )
void QskInputPanel::timerEvent( QTimerEvent* e ) void QskInputPanel::timerEvent( QTimerEvent* e )
{ {
if ( e->timerId() == m_data->repeatKeyTimerId ) if( e->timerId() == m_data->repeatKeyTimerId )
{ {
for ( auto it = m_data->activeKeys.begin(); it != m_data->activeKeys.end(); ) for( auto it = m_data->activeKeys.begin(); it != m_data->activeKeys.end(); )
{ {
if ( it->second.count >= 0 && it->second.count++ > 20 ) // ### use platform long-press hint if( it->second.count >= 0 && it->second.count++ > 20 ) // ### use platform long-press hint
{ {
const auto key = keyDataAt( it->second.keyIndex ).key & ~KeyStates; const auto key = keyDataAt( it->second.keyIndex ).key & ~KeyStates;
if ( !key || key == Qt::Key_unknown ) if( !key || key == Qt::Key_unknown )
{ {
it = m_data->activeKeys.erase( it ); it = m_data->activeKeys.erase( it );
continue; continue;
} }
if ( key == Qt::Key_ApplicationLeft || key == Qt::Key_ApplicationRight ) if( key == Qt::Key_ApplicationLeft || key == Qt::Key_ApplicationRight )
{ {
setCandidateOffset( m_data->candidateOffset setCandidateOffset( m_data->candidateOffset
+ ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) ); + ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) );
} }
else if ( !( key & KeyLocked ) ) // do not repeat locked keys else if( !( key & KeyLocked ) ) // do not repeat locked keys
{ {
// long press events could be emitted from here // long press events could be emitted from here
compose( key & ~KeyStates ); compose( key & ~KeyStates );
} }
} }
++it; ++it;
} }
} }
@ -722,29 +774,36 @@ void QskInputPanel::handleKey( int keyIndex )
const auto row = keyIndex / KeyCount; const auto row = keyIndex / KeyCount;
const auto column = keyIndex % KeyCount; const auto column = keyIndex % KeyCount;
if ( m_data->mode == LowercaseMode && !m_data->groups.isEmpty() && row == 0 ) if( m_data->mode == LowercaseMode && !m_data->groups.isEmpty() && row == 0 )
{ {
if ( key == Qt::Key_ApplicationLeft if( key == Qt::Key_ApplicationLeft
|| key == Qt::Key_ApplicationRight ) || key == Qt::Key_ApplicationRight )
{ {
setCandidateOffset( m_data->candidateOffset setCandidateOffset( m_data->candidateOffset
+ ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) ); + ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) );
return; return;
} }
const auto groupCount = m_data->groups.length(); const auto groupCount = m_data->groups.length();
if ( column < groupCount )
if( column < groupCount )
{
selectGroup( column ); selectGroup( column );
else if ( column < KeyCount ) }
else if( column < KeyCount )
{
selectCandidate( column - groupCount + m_data->candidateOffset ); selectCandidate( column - groupCount + m_data->candidateOffset );
}
else else
Q_UNREACHABLE(); // Handle the final key... {
Q_UNREACHABLE(); // Handle the final key...
}
return; return;
} }
// Mode-switching keys // Mode-switching keys
switch ( key ) switch( key )
{ {
case Qt::Key_CapsLock: case Qt::Key_CapsLock:
case Qt::Key_Kana_Lock: case Qt::Key_Kana_Lock:
@ -758,8 +817,8 @@ void QskInputPanel::handleKey( int keyIndex )
case Qt::Key_Mode_switch: // Cycle through modes, but skip caps case Qt::Key_Mode_switch: // Cycle through modes, but skip caps
setMode( static_cast< QskInputPanel::Mode >( setMode( static_cast< QskInputPanel::Mode >(
m_data->mode ? ( ( m_data->mode + 1 ) % QskInputPanel::ModeCount ) m_data->mode ? ( ( m_data->mode + 1 ) % QskInputPanel::ModeCount )
: SpecialCharacterMode ) ); : SpecialCharacterMode ) );
return; return;
default: default:
@ -779,18 +838,25 @@ void QskInputPanel::compose( Qt::Key key )
void QskInputPanel::selectGroup( int index ) void QskInputPanel::selectGroup( int index )
{ {
auto& topRow = m_data->keyTable[ m_data->mode ].data[ 0 ]; auto& topRow = m_data->keyTable[ m_data->mode ].data[ 0 ];
if ( m_data->selectedGroup >= 0 )
topRow[ m_data->selectedGroup ].key &= ~KeyLocked;
if ( m_data->selectedGroup == index ) if( m_data->selectedGroup >= 0 )
index = -1; // clear selection {
topRow[ m_data->selectedGroup ].key &= ~KeyLocked;
}
if( m_data->selectedGroup == index )
{
index = -1; // clear selection
}
m_data->selectedGroup = index; m_data->selectedGroup = index;
QGuiApplication::inputMethod()->invokeAction( QGuiApplication::inputMethod()->invokeAction(
static_cast< QInputMethod::Action >( SelectGroup ), m_data->selectedGroup + 1 ); static_cast< QInputMethod::Action >( SelectGroup ), m_data->selectedGroup + 1 );
if ( m_data->selectedGroup < 0 ) if( m_data->selectedGroup < 0 )
{
return; return;
}
topRow[ m_data->selectedGroup ].key |= KeyLocked; topRow[ m_data->selectedGroup ].key |= KeyLocked;
} }
@ -803,7 +869,7 @@ void QskInputPanel::selectCandidate( int index )
void QskInputPanel::updateLocale( const QLocale& locale ) void QskInputPanel::updateLocale( const QLocale& locale )
{ {
switch ( locale.language() ) switch( locale.language() )
{ {
case QLocale::Bulgarian: case QLocale::Bulgarian:
m_data->currentLayout = &qskInputPanelLayouts.bg; m_data->currentLayout = &qskInputPanelLayouts.bg;
@ -826,21 +892,24 @@ void QskInputPanel::updateLocale( const QLocale& locale )
break; break;
case QLocale::English: case QLocale::English:
{
switch ( locale.country() )
{ {
case QLocale::Canada: switch( locale.country() )
case QLocale::UnitedStates: {
case QLocale::UnitedStatesMinorOutlyingIslands: case QLocale::Canada:
case QLocale::UnitedStatesVirginIslands: case QLocale::UnitedStates:
m_data->currentLayout = &qskInputPanelLayouts.en_US; case QLocale::UnitedStatesMinorOutlyingIslands:
break; case QLocale::UnitedStatesVirginIslands:
default: m_data->currentLayout = &qskInputPanelLayouts.en_US;
m_data->currentLayout = &qskInputPanelLayouts.en_GB; break;
break;
default:
m_data->currentLayout = &qskInputPanelLayouts.en_GB;
break;
}
break;
} }
break;
}
case QLocale::Spanish: case QLocale::Spanish:
m_data->currentLayout = &qskInputPanelLayouts.es; m_data->currentLayout = &qskInputPanelLayouts.es;
break; break;
@ -925,12 +994,12 @@ void QskInputPanel::updateKeyData()
// Key data is in normalized coordinates // Key data is in normalized coordinates
const auto keyHeight = 1.0f / RowCount; const auto keyHeight = 1.0f / RowCount;
for ( const auto& keyLayout : *m_data->currentLayout ) for( const auto& keyLayout : *m_data->currentLayout )
{ {
auto& keyDataLayout = m_data->keyTable[ &keyLayout - *m_data->currentLayout ]; auto& keyDataLayout = m_data->keyTable[ &keyLayout - *m_data->currentLayout ];
qreal yPos = 0; qreal yPos = 0;
for ( int i = 0; i < RowCount; i++ ) for( int i = 0; i < RowCount; i++ )
{ {
auto& row = keyLayout.data[i]; auto& row = keyLayout.data[i];
auto& keyDataRow = keyDataLayout.data[ i ]; auto& keyDataRow = keyDataLayout.data[ i ];
@ -940,7 +1009,7 @@ void QskInputPanel::updateKeyData()
qreal xPos = 0; qreal xPos = 0;
qreal keyWidth = baseKeyWidth; qreal keyWidth = baseKeyWidth;
for ( const auto& key : row ) for( const auto& key : row )
{ {
auto& keyData = keyDataRow[ &key - row ]; auto& keyData = keyDataRow[ &key - row ];
keyData.key = key; keyData.key = key;

View File

@ -17,7 +17,7 @@ class QSK_EXPORT QskInputPanel : public QskControl
Q_PROPERTY( QRectF keyboardRect READ keyboardRect NOTIFY keyboardRectChanged ) Q_PROPERTY( QRectF keyboardRect READ keyboardRect NOTIFY keyboardRectChanged )
Q_PROPERTY( QString displayLanguageName READ displayLanguageName Q_PROPERTY( QString displayLanguageName READ displayLanguageName
NOTIFY displayLanguageNameChanged ) NOTIFY displayLanguageNameChanged )
using Inherited = QskControl; using Inherited = QskControl;