6#include "QskVirtualKeyboard.h"
7#include "QskPushButton.h"
9#include <qguiapplication.h>
11#include <qstylehints.h>
21 setFocusPolicy( Qt::TabFocus );
23 setSubcontrolProxy( QskPushButton::Panel, QskVirtualKeyboard::ButtonPanel );
24 setSubcontrolProxy( QskPushButton::Text, QskVirtualKeyboard::ButtonText );
32 void setKey(
int key )
41 static bool qskIsAutorepeat(
int key )
44 ( key != Qt::Key_Return ) &&
45 ( key != Qt::Key_Enter ) &&
46 ( key != Qt::Key_Shift ) &&
47 ( key != Qt::Key_CapsLock ) &&
48 ( key != Qt::Key_Mode_switch ) );
57class QskVirtualKeyboard::PrivateData
64 const QskVirtualKeyboardLayouts::Layout* currentLayout =
nullptr;
65 QskVirtualKeyboard::Mode mode = QskVirtualKeyboard::LowercaseMode;
67 QVector< Button* > keyButtons;
71QskVirtualKeyboard::QskVirtualKeyboard( QQuickItem* parent )
73 , m_data( new PrivateData )
75 setPolishOnResize(
true );
76 initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Fixed );
78#define LOWER( x ) int( x + 32 )
81#include "QskVirtualKeyboardLayouts.hpp"
88 this, &QskVirtualKeyboard::updateLocale );
90 updateLocale( locale() );
92 setSubcontrolProxy( QskBox::Panel, Panel );
95QskVirtualKeyboard::~QskVirtualKeyboard()
99void QskVirtualKeyboard::setMode( QskVirtualKeyboard::Mode mode )
104 Q_EMIT modeChanged( m_data->mode );
107QskVirtualKeyboard::Mode QskVirtualKeyboard::mode()
const
112QSizeF QskVirtualKeyboard::layoutSizeHint(
113 Qt::SizeHint which,
const QSizeF& constraint )
const
115 if ( which != Qt::PreferredSize )
118 const qreal ratio = qreal( rowCount() ) / columnCount();
120 qreal w = constraint.width();
121 qreal h = constraint.height();
125 const auto padding =
innerPadding( Panel, QSizeF( h, h ) );
126 const auto dw = padding.left() + padding.right();
127 const auto dh = padding.top() + padding.bottom();
129 w = ( h - dh ) / ratio + dw;
136 const auto padding =
innerPadding( Panel, QSizeF( w, w ) );
137 const auto dw = padding.left() + padding.right();
138 const auto dh = padding.top() + padding.bottom();
140 h = ( w - dw ) * ratio + dh;
143 return QSizeF( w, h );
146qreal QskVirtualKeyboard::keyStretch(
int key )
const
150 case Qt::Key_Backspace:
152 case Qt::Key_CapsLock:
159 case Qt::Key_Mode_switch:
169bool QskVirtualKeyboard::isKeyVisible(
int key )
const
174QString QskVirtualKeyboard::textForKey(
int key )
const
179 case Qt::Key_Backspace:
180 case Qt::Key_Muhenkan:
181 return QChar( 0x232B );
183 case Qt::Key_CapsLock:
184 case Qt::Key_Kana_Lock:
185 return QChar( 0x21E7 );
188 case Qt::Key_Kana_Shift:
189 return QChar( 0x2B06 );
191 case Qt::Key_Mode_switch:
192 return QChar( 0x2026 );
196 return QChar( 0x23CE );
199 return QChar( 0x2190 );
202 return QChar( 0x2192 );
204 case Qt::Key_ApplicationLeft:
205 return QChar( 0x2B05 );
207 case Qt::Key_ApplicationRight:
208 return QChar( 0x27A1 );
215QskVirtualKeyboard::KeyType QskVirtualKeyboard::typeForKey(
int key )
const
223 case Qt::Key_Backspace:
224 return BackspaceType;
227 case Qt::Key_CapsLock:
228 return CapsSwitchType;
230 case Qt::Key_Mode_switch:
231 return ModeSwitchType;
235 return SpecialCharacterType;
242void QskVirtualKeyboard::updateLayout()
249 const auto totalVSpacing = ( rowCount() - 1 ) * spacing;
251 const auto keyHeight = ( r.height() - totalVSpacing ) / rowCount();
253 qreal yPos = r.top();
255 const auto& page = ( *m_data->currentLayout )[ mode() ];
257 for (
int i = 0; i < page.size(); i++ )
259 const QVector< int > row = page[ i ];
262 auto totalHSpacing = -spacing;
265 for (
int j = 0; j < row.size(); j++ )
268 totalHSpacing += spacing;
272 const auto baseKeyWidth = ( r.width() - totalHSpacing ) / rowStretch( row );
273 qreal xPos = r.left();
275 for (
int j = 0; j < columnCount(); j++ )
277 auto button = m_data->keyButtons[ i * columnCount() + j ];
281 const int key = row[ j ];
282 button->setVisible( isKeyVisible( key ) );
284 if ( button->isVisible() )
286 const qreal keyWidth = baseKeyWidth * keyStretch( key );
288 const QRectF
rect( xPos, yPos, keyWidth, keyHeight );
290 button->setGeometry(
rect );
291 button->setAutoRepeat( qskIsAutorepeat( key ) );
292 button->setKey( key );
293 button->setText( textForKey( key ) );
295 const auto type = typeForKey( key );
296 const auto emphasis = emphasisForType( type );
297 button->setEmphasis( emphasis );
299 xPos += keyWidth + spacing;
304 button->setVisible(
false );
308 yPos += keyHeight + spacing;
312bool QskVirtualKeyboard::hasKey(
int keyCode )
const
314 return m_data->keyCodes.contains( keyCode );
317int QskVirtualKeyboard::rowCount()
const
319 return m_data->rowCount;
322void QskVirtualKeyboard::setRowCount(
int rowCount )
324 m_data->rowCount = rowCount;
328int QskVirtualKeyboard::columnCount()
const
330 return m_data->columnCount;
333void QskVirtualKeyboard::setColumnCount(
int columnCount )
335 m_data->columnCount = columnCount;
341 return m_data->layouts;
346 m_data->layouts = layouts;
349void QskVirtualKeyboard::ensureButtons()
351 const int newButtonSize = rowCount() * columnCount();
352 const int oldButtonSize = m_data->keyButtons.size();
354 if( newButtonSize == oldButtonSize )
357 const auto hints = QGuiApplication::styleHints();
359 auto autoRepeatInterval = 1000.0;
360#if QT_VERSION >= QT_VERSION_CHECK( 6, 5, 0 )
361 autoRepeatInterval /= hints->keyboardAutoRepeatRateF();
363 autoRepeatInterval /= hints->keyboardAutoRepeatRate();
366 m_data->keyButtons.reserve( rowCount() * columnCount() );
368 for(
int i = 0; i < rowCount(); i++ )
370 for(
int j = 0; j < columnCount(); j++ )
372 const int index = i * columnCount() + j;
374 if( index >= m_data->keyButtons.size() )
376 auto button =
new Button(
this );
377 button->installEventFilter(
this );
379 button->setAutoRepeat(
false );
380 button->setAutoRepeatDelay( 500 );
381 button->setAutoRepeatInterval( autoRepeatInterval );
383 connect( button, &QskPushButton::pressed,
384 this, &QskVirtualKeyboard::buttonPressed );
386 m_data->keyButtons += button;
391 while( m_data->keyButtons.size() > newButtonSize )
393 auto* button = m_data->keyButtons.takeLast();
394 button->deleteLater();
398void QskVirtualKeyboard::buttonPressed()
400 const auto button =
static_cast< const Button*
>( sender() );
401 if ( button ==
nullptr )
404 const int key = button->key();
409 case Qt::Key_CapsLock:
410 case Qt::Key_Kana_Lock:
412 setMode( UppercaseMode );
417 case Qt::Key_Kana_Shift:
419 setMode( LowercaseMode );
423 case Qt::Key_Mode_switch:
425 setMode(
static_cast< QskVirtualKeyboard::Mode
>(
426 m_data->mode ? ( ( m_data->mode + 1 ) % QskVirtualKeyboard::ModeCount )
427 : SpecialCharacterMode ) );
433 Q_EMIT keySelected( key );
438void QskVirtualKeyboard::updateKeyCodes()
440 m_data->keyCodes = {};
441 m_data->keyCodes.reserve( rowCount() * columnCount() );
443 const auto layout = *m_data->currentLayout;
445 for (
int mode = 0; mode < layout.size(); mode++ )
447 const auto& page = layout[ mode ];
449 for (
int i = 0; i < page.size(); i++ )
451 const auto& row = page[ i ];
453 for (
int j = 0; j < row.size(); j++ )
455 m_data->keyCodes += row[ j ];
461qreal QskVirtualKeyboard::rowStretch(
const QVector< int >& row )
465 for (
const int& key : row )
472 stretch += keyStretch( key );
475 if ( stretch == 0.0 )
477 stretch = columnCount();
483void QskVirtualKeyboard::updateLocale(
const QLocale& locale )
485 const QskVirtualKeyboardLayouts::Layout* newLayout =
nullptr;
487 switch (
locale.language() )
489 case QLocale::Bulgarian:
490 newLayout = &m_data->layouts.bg;
494 newLayout = &m_data->layouts.cs;
497 case QLocale::German:
498 newLayout = &m_data->layouts.de;
501 case QLocale::Danish:
502 newLayout = &m_data->layouts.da;
506 newLayout = &m_data->layouts.el;
509 case QLocale::English:
511 const auto territory =
512#if QT_VERSION >= QT_VERSION_CHECK( 6, 2, 0 )
520 case QLocale::Canada:
521 case QLocale::UnitedStates:
522 case QLocale::UnitedStatesMinorOutlyingIslands:
523 case QLocale::UnitedStatesVirginIslands:
524 newLayout = &m_data->layouts.en_US;
528 newLayout = &m_data->layouts.en_GB;
535 case QLocale::Spanish:
536 newLayout = &m_data->layouts.es;
539 case QLocale::Finnish:
540 newLayout = &m_data->layouts.fi;
543 case QLocale::French:
544 newLayout = &m_data->layouts.fr;
547 case QLocale::Hungarian:
548 newLayout = &m_data->layouts.hu;
551 case QLocale::Italian:
552 newLayout = &m_data->layouts.it;
555 case QLocale::Japanese:
556 newLayout = &m_data->layouts.ja;
559 case QLocale::Latvian:
560 newLayout = &m_data->layouts.lv;
563 case QLocale::Lithuanian:
564 newLayout = &m_data->layouts.lt;
568 newLayout = &m_data->layouts.nl;
571 case QLocale::Portuguese:
572 newLayout = &m_data->layouts.pt;
575 case QLocale::Romanian:
576 newLayout = &m_data->layouts.ro;
579 case QLocale::Russian:
580 newLayout = &m_data->layouts.ru;
583 case QLocale::Slovenian:
584 newLayout = &m_data->layouts.sl;
587 case QLocale::Slovak:
588 newLayout = &m_data->layouts.sk;
591 case QLocale::Turkish:
592 newLayout = &m_data->layouts.tr;
595 case QLocale::Chinese:
596 newLayout = &m_data->layouts.zh;
600 newLayout = &m_data->layouts.en_US;
604 qWarning() <<
"QskVirtualKeyboard: unsupported locale:" <<
locale;
605 newLayout = &m_data->layouts.en_US;
608 if ( newLayout != m_data->currentLayout )
610 m_data->currentLayout = newLayout;
613 setMode( LowercaseMode );
615 Q_EMIT keyboardLayoutChanged();
619QskPushButton::Emphasis QskVirtualKeyboard::emphasisForType( KeyType type )
624 return QskPushButton::VeryHighEmphasis;
628 return QskPushButton::HighEmphasis;
631 return QskPushButton::LowEmphasis;
633 case SpecialCharacterType:
634 return QskPushButton::VeryLowEmphasis;
637 return QskPushButton::NoEmphasis;
641#include "moc_QskVirtualKeyboard.cpp"
void localeChanged(const QLocale &)
QRectF layoutRect() const
qreal spacingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a spacing hint.
QMarginsF innerPadding(QskAspect, const QSizeF &) const
Calculate the padding from attributes for the given aspect.