keyboard: Write the keyboard model and layout settings to the root mount point.

This is implemented as a new SetKeyboardLayout job that does the work.

Portions of the code are adapted from systemd-localed's source code,
which is under a compatible license (LGPLv2.1+, can be converted to our
GPLv3+ license). I ported it from C to to C++/Qt and made some minor
tweaks to the mapping logic (from X11 to vconsole layouts) though.

Fixes #31.

Tested on a Fedora Remix (Kannolo 21) with the default module settings
(finds the converted X11 keymaps for the virtual console) and with
convertedKeymapPath: "" (does the legacy keymap conversion as expected).
main
Kevin Kofler 10 years ago
parent 54feddb330
commit 4f9f7d7858

@ -6,6 +6,7 @@ calamares_add_plugin( keyboard
SOURCES SOURCES
KeyboardViewStep.cpp KeyboardViewStep.cpp
KeyboardPage.cpp KeyboardPage.cpp
SetKeyboardLayoutJob.cpp
keyboardwidget/keyboardglobal.cpp keyboardwidget/keyboardglobal.cpp
keyboardwidget/keyboardpreview.cpp keyboardwidget/keyboardpreview.cpp
UI UI

@ -24,6 +24,7 @@
#include "ui_KeyboardPage.h" #include "ui_KeyboardPage.h"
#include "keyboardwidget/keyboardpreview.h" #include "keyboardwidget/keyboardpreview.h"
#include "SetKeyboardLayoutJob.h"
#include "GlobalStorage.h" #include "GlobalStorage.h"
#include "JobQueue.h" #include "JobQueue.h"
@ -188,6 +189,22 @@ KeyboardPage::prettyStatus() const
} }
QList< Calamares::job_ptr >
KeyboardPage::createJobs()
{
QList< Calamares::job_ptr > list;
QString selectedModel = m_models.value( ui->comboBoxModel->currentText(),
"pc105" );
Calamares::Job* j = new SetKeyboardLayoutJob( selectedModel,
m_selectedLayout,
m_selectedVariant );
list.append( Calamares::job_ptr( j ) );
return list;
}
void void
KeyboardPage::finalize() KeyboardPage::finalize()
{ {

@ -25,6 +25,8 @@
#include "keyboardwidget/keyboardglobal.h" #include "keyboardwidget/keyboardglobal.h"
#include "Typedefs.h"
#include <QListWidgetItem> #include <QListWidgetItem>
#include <QWidget> #include <QWidget>
@ -46,6 +48,8 @@ public:
QString prettyStatus() const; QString prettyStatus() const;
QList< Calamares::job_ptr > createJobs();
void finalize(); void finalize();
protected slots: protected slots:

@ -18,6 +18,9 @@
#include "KeyboardViewStep.h" #include "KeyboardViewStep.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
#include "KeyboardPage.h" #include "KeyboardPage.h"
@ -97,7 +100,7 @@ KeyboardViewStep::isAtEnd() const
QList< Calamares::job_ptr > QList< Calamares::job_ptr >
KeyboardViewStep::jobs() const KeyboardViewStep::jobs() const
{ {
return QList< Calamares::job_ptr >(); return m_jobs;
} }
@ -105,5 +108,38 @@ void
KeyboardViewStep::onLeave() KeyboardViewStep::onLeave()
{ {
m_widget->finalize(); m_widget->finalize();
m_jobs = m_widget->createJobs();
m_prettyStatus = m_widget->prettyStatus(); m_prettyStatus = m_widget->prettyStatus();
} }
void
KeyboardViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
// Save the settings to the global settings for the SetKeyboardLayoutJob to use
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
if ( configurationMap.contains( "xOrgConfFileName" ) &&
configurationMap.value( "xOrgConfFileName" ).type() == QVariant::String &&
!configurationMap.value( "xOrgConfFileName" ).toString().isEmpty() )
{
gs->insert( "keyboardXOrgConfFileName",
configurationMap.value( "xOrgConfFileName" ) );
}
else
{
gs->insert( "keyboardXOrgConfFileName", "00-keyboard.conf" );
}
if ( configurationMap.contains( "convertedKeymapPath" ) &&
configurationMap.value( "convertedKeymapPath" ).type() == QVariant::String &&
!configurationMap.value( "convertedKeymapPath" ).toString().isEmpty() )
{
gs->insert( "keyboardConvertedKeymapPath",
configurationMap.value( "convertedKeymapPath" ) );
}
else
{
gs->remove( "keyboardConvertedKeymapPath" );
}
}

@ -54,10 +54,14 @@ public:
void onLeave() override; void onLeave() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
private: private:
KeyboardPage* m_widget; KeyboardPage* m_widget;
bool m_nextEnabled; bool m_nextEnabled;
QString m_prettyStatus; QString m_prettyStatus;
QList< Calamares::job_ptr > m_jobs;
}; };
#endif // KEYBOARDVIEWSTEP_H #endif // KEYBOARDVIEWSTEP_H

@ -0,0 +1,255 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Teo Mrnjavac <teo@kde.org>
* Copyright 2014, Kevin Kofler <kevin.kofler@chello.at>
*
* Portions from systemd (localed.c):
* Copyright 2011 Lennart Poettering
* Copyright 2013 Kay Sievers
* (originally under LGPLv2.1+, used under the LGPL to GPL conversion clause)
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#include <SetKeyboardLayoutJob.h>
#include "JobQueue.h"
#include "GlobalStorage.h"
#include "utils/Logger.h"
#include "utils/CalamaresUtilsSystem.h"
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QSettings>
SetKeyboardLayoutJob::SetKeyboardLayoutJob( const QString& model,
const QString& layout,
const QString& variant )
: Calamares::Job()
, m_model( model )
, m_layout( layout )
, m_variant( variant )
{
}
QString
SetKeyboardLayoutJob::prettyName() const
{
return tr( "Set keyboard model to %1, layout to %2-%3" ).arg( m_model )
.arg( m_layout )
.arg( m_variant );
}
QString
SetKeyboardLayoutJob::findConvertedKeymap( const QString& convertedKeymapPath ) const {
// No search path supplied, assume the distribution does not provide
// converted keymaps
if ( convertedKeymapPath.isEmpty() )
return QString();
QDir convertedKeymapDir( convertedKeymapPath );
QString name = m_variant.isEmpty() ? m_layout : (m_layout + '-' + m_variant);
if ( convertedKeymapDir.exists( name + ".map" )
|| convertedKeymapDir.exists( name + ".map.gz" ) ) {
cDebug() << "Found converted keymap" << name;
return name;
}
return QString();
}
QString
SetKeyboardLayoutJob::findLegacyKeymap() const {
int bestMatching = 0;
QString name;
QFile file( ":/kbd-model-map" );
file.open( QIODevice::ReadOnly | QIODevice::Text );
QTextStream stream( &file );
while ( !stream.atEnd() ) {
QString line = stream.readLine().trimmed();
if ( line.isEmpty() || line.startsWith( '#' ) )
continue;
QStringList mapping = line.split( '\t', QString::SkipEmptyParts );
if ( mapping.size() < 5 )
continue;
int matching = 0;
// Determine how well matching this entry is
// We assume here that we have one X11 layout. If the UI changes to
// allow more than one layout, this should change too.
if ( m_layout == mapping[1] )
// If we got an exact match, this is best
matching = 10;
// Look for an entry whose first layout matches ours
else if ( mapping[1].startsWith( m_layout + ',' ) )
matching = 5;
if (matching > 0) {
if ( m_model.isEmpty() || m_model == mapping[2] )
matching++;
QString mappingVariant = mapping[3];
if ( mappingVariant == "-" )
mappingVariant = QString();
else if ( mappingVariant.startsWith( ',' ) )
mappingVariant.remove( 1, 0 );
if ( m_variant == mappingVariant )
matching++;
// We ignore mapping[4], the xkb options, for now. If we ever
// allow setting options in the UI, we should match them here.
}
// The best matching entry so far, then let's save that
if ( matching >= qMax( bestMatching, 1 ) ) {
cDebug() << "Found legacy keymap" << mapping[0]
<< "with score" << matching;
if ( matching > bestMatching ) {
bestMatching = matching;
name = mapping[0];
}
}
}
return name;
}
bool
SetKeyboardLayoutJob::writeVConsoleData( const QString& vconsoleConfPath,
const QString& convertedKeymapPath ) const {
QString keymap = findConvertedKeymap( convertedKeymapPath );
if ( keymap.isEmpty() )
keymap = findLegacyKeymap();
if ( keymap.isEmpty() ) {
cDebug() << "Trying to use X11 layout" << m_layout
<< "as the virtual console layout";
keymap = m_layout;
}
QStringList existingLines;
// Read in the existing vconsole.conf, if it exists
QFile file( vconsoleConfPath );
if ( file.exists() ) {
file.open( QIODevice::ReadOnly | QIODevice::Text );
QTextStream stream( &file );
while ( !stream.atEnd() )
existingLines << stream.readLine();
file.close();
if ( stream.status() != QTextStream::Ok )
return false;
}
// Write out the existing lines and replace the KEYMAP= line
file.open( QIODevice::WriteOnly | QIODevice::Text );
QTextStream stream( &file );
bool found = false;
foreach ( const QString& existingLine, existingLines ) {
if ( existingLine.trimmed().startsWith( "KEYMAP=" ) ) {
stream << "KEYMAP=" << keymap << '\n';
found = true;
} else
stream << existingLine << '\n';
}
// Add a KEYMAP= line if there wasn't any
if (!found)
stream << "KEYMAP=" << keymap << '\n';
stream.flush();
file.close();
return (stream.status() == QTextStream::Ok);
}
bool
SetKeyboardLayoutJob::writeX11Data( const QString& keyboardConfPath ) const {
QFile file( keyboardConfPath );
file.open( QIODevice::WriteOnly | QIODevice::Text );
QTextStream stream( &file );
stream << "# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
"# manually too freely.\n"
"Section \"InputClass\"\n"
" Identifier \"system-keyboard\"\n"
" MatchIsKeyboard \"on\"\n";
if ( !m_layout.isEmpty() )
stream << " Option \"XkbLayout\" \"" << m_layout << "\"\n";
if ( !m_model.isEmpty() )
stream << " Option \"XkbModel\" \"" << m_model << "\"\n";
if ( !m_variant.isEmpty() )
stream << " Option \"XkbVariant\" \"" << m_variant << "\"\n";
stream << "EndSection\n";
stream.flush();
file.close();
return (stream.status() == QTextStream::Ok);
}
Calamares::JobResult
SetKeyboardLayoutJob::exec()
{
// Read the location of the destination's / in the host file system from
// the global settings
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
QDir destDir( gs->value( "rootMountPoint" ).toString() );
// Get the path to the destination's /etc/vconsole.conf
QString vconsoleConfPath = destDir.absoluteFilePath( "etc/vconsole.conf" );
// Get the path to the destination's /etc/X11/xorg.conf.d/00-keyboard.conf
QString xorgConfDPath = destDir.absoluteFilePath( "etc/X11/xorg.conf.d" );
destDir.mkpath( xorgConfDPath );
QString keyboardConfFile = gs->value( "keyboardXOrgConfFileName" ).toString();
QString keyboardConfPath = QDir( xorgConfDPath )
.absoluteFilePath( keyboardConfFile );
// Get the path to the destination's path to the converted key mappings
QString convertedKeymapPath;
QString convertedKeymapPathSetting
= gs->value( "keyboardConvertedKeymapPath" ).toString();
if ( !convertedKeymapPathSetting.isEmpty() ) {
while ( convertedKeymapPathSetting.startsWith( '/' ) )
convertedKeymapPathSetting.remove( 0, 1 );
convertedKeymapPath = destDir.absoluteFilePath( convertedKeymapPathSetting );
}
if ( !writeVConsoleData( vconsoleConfPath, convertedKeymapPath ) )
return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for the virtual console." ),
tr( "Failed to write to %1" ).arg( vconsoleConfPath ) );
if ( !writeX11Data( keyboardConfPath ) )
return Calamares::JobResult::error( tr( "Failed to write keyboard configuration for X11." ),
tr( "Failed to write to %1" ).arg( keyboardConfPath ) );
return Calamares::JobResult::ok();
}

@ -0,0 +1,49 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Teo Mrnjavac <teo@kde.org>
* Copyright 2014, Kevin Kofler <kevin.kofler@chello.at>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Calamares is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SETKEYBOARDLAYOUTJOB_H
#define SETKEYBOARDLAYOUTJOB_H
#include <Job.h>
class SetKeyboardLayoutJob : public Calamares::Job
{
Q_OBJECT
public:
SetKeyboardLayoutJob( const QString& model,
const QString& layout,
const QString& variant );
QString prettyName() const override;
Calamares::JobResult exec() override;
private:
QString findConvertedKeymap( const QString& convertedKeymapPath ) const;
QString findLegacyKeymap() const;
bool writeVConsoleData( const QString& vconsoleConfPath,
const QString& convertedKeymapPath ) const;
bool writeX11Data( const QString& keyboardConfPath ) const;
QString m_model;
QString m_layout;
QString m_variant;
};
#endif /* SETKEYBOARDLAYOUTJOB_H */

@ -0,0 +1,66 @@
# Copied from systemd-localed
# (originally under LGPLv2.1+, used under the LGPL to GPL conversion clause)
# Generated from system-config-keyboard's model list
# consolelayout xlayout xmodel xvariant xoptions
sg ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp
nl nl pc105 - terminate:ctrl_alt_bksp
mk-utf mk,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
trq tr pc105 - terminate:ctrl_alt_bksp
uk gb pc105 - terminate:ctrl_alt_bksp
is-latin1 is pc105 - terminate:ctrl_alt_bksp
de de pc105 - terminate:ctrl_alt_bksp
la-latin1 latam pc105 - terminate:ctrl_alt_bksp
us us pc105+inet - terminate:ctrl_alt_bksp
ko kr pc105 - terminate:ctrl_alt_bksp
ro-std ro pc105 std terminate:ctrl_alt_bksp
de-latin1 de pc105 - terminate:ctrl_alt_bksp
slovene si pc105 - terminate:ctrl_alt_bksp
hu101 hu pc105 qwerty terminate:ctrl_alt_bksp
jp106 jp jp106 - terminate:ctrl_alt_bksp
croat hr pc105 - terminate:ctrl_alt_bksp
it2 it pc105 - terminate:ctrl_alt_bksp
hu hu pc105 - terminate:ctrl_alt_bksp
sr-latin rs pc105 latin terminate:ctrl_alt_bksp
fi fi pc105 - terminate:ctrl_alt_bksp
fr_CH ch pc105 fr terminate:ctrl_alt_bksp
dk-latin1 dk pc105 - terminate:ctrl_alt_bksp
fr fr pc105 - terminate:ctrl_alt_bksp
it it pc105 - terminate:ctrl_alt_bksp
ua-utf ua,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
fr-latin1 fr pc105 - terminate:ctrl_alt_bksp
sg-latin1 ch pc105 de_nodeadkeys terminate:ctrl_alt_bksp
be-latin1 be pc105 - terminate:ctrl_alt_bksp
dk dk pc105 - terminate:ctrl_alt_bksp
fr-pc fr pc105 - terminate:ctrl_alt_bksp
bg_pho-utf8 bg,us pc105 ,phonetic terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
it-ibm it pc105 - terminate:ctrl_alt_bksp
cz-us-qwertz cz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
br-abnt2 br abnt2 - terminate:ctrl_alt_bksp
ro ro pc105 - terminate:ctrl_alt_bksp
us-acentos us pc105 intl terminate:ctrl_alt_bksp
pt-latin1 pt pc105 - terminate:ctrl_alt_bksp
ro-std-cedilla ro pc105 std_cedilla terminate:ctrl_alt_bksp
tj_alt-UTF8 tj pc105 - terminate:ctrl_alt_bksp
de-latin1-nodeadkeys de pc105 nodeadkeys terminate:ctrl_alt_bksp
no no pc105 - terminate:ctrl_alt_bksp
bg_bds-utf8 bg,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
dvorak us pc105 dvorak terminate:ctrl_alt_bksp
dvorak us pc105 dvorak-alt-intl terminate:ctrl_alt_bksp
ru ru,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
cz-lat2 cz pc105 qwerty terminate:ctrl_alt_bksp
pl2 pl pc105 - terminate:ctrl_alt_bksp
es es pc105 - terminate:ctrl_alt_bksp
ro-cedilla ro pc105 cedilla terminate:ctrl_alt_bksp
ie ie pc105 - terminate:ctrl_alt_bksp
et ee pc105 - terminate:ctrl_alt_bksp
sk-qwerty sk pc105 - terminate:ctrl_alt_bksp,qwerty
fr-latin9 fr pc105 latin9 terminate:ctrl_alt_bksp
fr_CH-latin1 ch pc105 fr terminate:ctrl_alt_bksp
cf ca pc105 - terminate:ctrl_alt_bksp
sv-latin1 se pc105 - terminate:ctrl_alt_bksp
sr-cy rs pc105 - terminate:ctrl_alt_bksp
gr gr,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
by by,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
il il pc105 - terminate:ctrl_alt_bksp
kazakh kz,us pc105 - terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
lt lt pc105 - terminate:ctrl_alt_bksp

@ -0,0 +1,7 @@
---
# The name of the file to write to /etc/X11/xorg.conf.d
# The default value is the name used by upstream systemd-localed.
xOrgConfFileName: "00-keyboard.conf"
# The path to search for keymaps converted from X11 to kbd format
# Leave this empty if the setting does not make sense on your distribution.
convertedKeymapPath: "/lib/kbd/keymaps/xkb"

@ -1,5 +1,6 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>kbd-model-map</file>
<file>images/restore.png</file> <file>images/restore.png</file>
</qresource> </qresource>
</RCC> </RCC>

Loading…
Cancel
Save