From 17b964701606bdbf620e7229840768568c6c6096 Mon Sep 17 00:00:00 2001 From: Artem Grinev Date: Sun, 25 Oct 2020 05:14:42 +0300 Subject: [PATCH] [keyboard] Support for additional layout if current layout is not ASCII- capable in live system --- src/modules/keyboard/Config.cpp | 132 ++++++++++++++++++++++++- src/modules/keyboard/Config.h | 12 +++ src/modules/keyboard/keyboard.qrc | 1 + src/modules/keyboard/non-ascii-layouts | 4 + 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/modules/keyboard/non-ascii-layouts diff --git a/src/modules/keyboard/Config.cpp b/src/modules/keyboard/Config.cpp index 7f7eb7b27..4e59b5fda 100644 --- a/src/modules/keyboard/Config.cpp +++ b/src/modules/keyboard/Config.cpp @@ -49,6 +49,104 @@ xkbmap_layout_args( const QString& layout, const QString& variant ) return r; } +static inline QStringList +xkbmap_layout_args( const QList> layoutsAndVariantsList, const QString& switchOption = "grp:alt_shift_toggle") +{ + QStringList layouts; + QStringList variants; + + for( auto& [layout,variant] : layoutsAndVariantsList ) + { + layouts.append(layout); + variants.append(variant); + } + + QStringList r{ "-layout", layouts.join( "," ) }; + + if ( !variants.isEmpty() ) + { + r << "-variant" << variants.join( "," ); + } + + if ( !switchOption.isEmpty()) + { + r << "-option" << switchOption; + } + + return r; +} + +static inline QString +xkbmap_query_grp_option() +{ + QProcess setxkbmapQuery; + setxkbmapQuery.start( "setxkbmap", { "-query" } ); + setxkbmapQuery.waitForFinished(); + + QString outputLine; + + do + { + outputLine = setxkbmapQuery.readLine(); + } + while( !setxkbmapQuery.atEnd() || !outputLine.startsWith("options:") ); + + if( !outputLine.startsWith("options:") ) + { + return QString(); + } + + int index = outputLine.indexOf("grp:"); + + if( index == -1 ) + { + return QString(); + } + + //it's either in the end of line or before the other option so \s or , + int lastIndex = outputLine.indexOf( QRegExp("[\\s,]"), index ); + + return outputLine.mid( index, lastIndex-1 ); +} + +AdditionalLayoutInfo Config::getAdditionalLayoutInfo( const QString &layout, bool* found ) +{ + QFile layoutTable(":/non-ascii-layouts"); + + if(!layoutTable.open(QIODevice::ReadOnly | QIODevice::Text)) { + cError() << "Non-ASCII layout table could not be opened"; + *found = false; + return {}; + } + + QString tableLine; + + do + { + tableLine = layoutTable.readLine(); + } + while( !layoutTable.atEnd() || !tableLine.startsWith(layout) ); + + if( !tableLine.startsWith(layout) ){ + *found = false; + return {}; + } + + *found = true; + + QStringList tableEntries = tableLine.split(" ", SplitSkipEmptyParts); + + AdditionalLayoutInfo r; + + r.name = tableEntries[0]; + r.additionalLayout = tableEntries[1]; + r.additionalVariant = tableEntries[2]; + + r.vconsoleKeymap = tableEntries[3]; + + return r; +} + Config::Config( QObject* parent ) : QObject( parent ) , m_keyboardModelsModel( new KeyboardModelsModel( this ) ) @@ -82,8 +180,31 @@ Config::Config( QObject* parent ) } connect( &m_setxkbmapTimer, &QTimer::timeout, this, [=] { - QProcess::execute( "setxkbmap", xkbmap_layout_args( m_selectedLayout, m_selectedVariant ) ); - cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant; + bool isNotAsciiCapable = false; + AdditionalLayoutInfo info = getAdditionalLayoutInfo( m_selectedLayout, &isNotAsciiCapable ); + + if(isNotAsciiCapable) + { + m_selectedLayoutsAdditionalLayoutInfo = info; + QString switchOption = xkbmap_query_grp_option(); + + QProcess::execute( "setxkbmap", xkbmap_layout_args( { + {m_selectedLayout, m_selectedVariant}, + {info.additionalLayout, info.additionalVariant} + }, + switchOption.isEmpty()?"grp:alt_shift_toggle":QString() ) + ); + cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant + << "(added " << info.additionalLayout << "-" << info.additionalVariant << " since target layout is not ASCII-capable)"; + + + } + else + { + m_selectedLayoutsAdditionalLayoutInfo = AdditionalLayoutInfo(); + QProcess::execute( "setxkbmap", xkbmap_layout_args( m_selectedLayout, m_selectedVariant ) ); + cDebug() << "xkbеmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant; + } m_setxkbmapTimer.disconnect( this ); } ); m_setxkbmapTimer.start( QApplication::keyboardInputInterval() ); @@ -372,6 +493,13 @@ Config::finalize() { gs->insert( "keyboardLayout", m_selectedLayout ); gs->insert( "keyboardVariant", m_selectedVariant ); //empty means default variant + + if ( !m_selectedLayoutsAdditionalLayoutInfo.name.isEmpty() ) + { + gs->insert( "keyboardAdditionalLayout", m_selectedLayoutsAdditionalLayoutInfo.additionalLayout); + gs->insert( "keyboardAdditionalLayout", m_selectedLayoutsAdditionalLayoutInfo.additionalVariant); + gs->insert( "keyboardVConsoleKeymap", m_selectedLayoutsAdditionalLayoutInfo.vconsoleKeymap ); + } } //FIXME: also store keyboard model for something? diff --git a/src/modules/keyboard/Config.h b/src/modules/keyboard/Config.h index 9a3a3a013..34d719d1b 100644 --- a/src/modules/keyboard/Config.h +++ b/src/modules/keyboard/Config.h @@ -20,6 +20,15 @@ #include #include +struct AdditionalLayoutInfo { + QString name; + + QString additionalLayout; + QString additionalVariant; + + QString vconsoleKeymap; +}; + class Config : public QObject { Q_OBJECT @@ -41,6 +50,8 @@ public: void setConfigurationMap( const QVariantMap& configurationMap ); + static AdditionalLayoutInfo getAdditionalLayoutInfo( const QString& layout, bool* found ); + private: void guessLayout( const QStringList& langParts ); void updateVariants( const QPersistentModelIndex& currentItem, QString currentVariant = QString() ); @@ -52,6 +63,7 @@ private: QString m_selectedLayout; QString m_selectedModel; QString m_selectedVariant; + AdditionalLayoutInfo m_selectedLayoutsAdditionalLayoutInfo; QTimer m_setxkbmapTimer; // From configuration diff --git a/src/modules/keyboard/keyboard.qrc b/src/modules/keyboard/keyboard.qrc index dd211e630..4283d8190 100644 --- a/src/modules/keyboard/keyboard.qrc +++ b/src/modules/keyboard/keyboard.qrc @@ -2,5 +2,6 @@ kbd-model-map images/restore.png + non-ascii-layouts diff --git a/src/modules/keyboard/non-ascii-layouts b/src/modules/keyboard/non-ascii-layouts new file mode 100644 index 000000000..83935c190 --- /dev/null +++ b/src/modules/keyboard/non-ascii-layouts @@ -0,0 +1,4 @@ +# Layouts stored here need additional layout (usually us) to provide ASCII support for user + +#layout additional-layout additional-variant vconsole-keymap +ru us - ruwin_alt_sh-UTF-8