mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.6 KiB
174 lines
5.6 KiB
/* |
|
SPDX-FileCopyrightText: 2010 Andriy Rysin <[email protected]> |
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
*/ |
|
|
|
#include "xkb_helper.h" |
|
#include "debug.h" |
|
|
|
#include <QDebug> |
|
#include <QDir> |
|
#include <QElapsedTimer> |
|
#include <QFile> |
|
#include <QProcess> |
|
#include <QStandardPaths> |
|
#include <QString> |
|
#include <QStringList> |
|
#include <QTime> |
|
#include <QX11Info> |
|
|
|
#include "keyboard_config.h" |
|
#include "keyboardsettings.h" |
|
|
|
static const char SETXKBMAP_EXEC[] = "setxkbmap"; |
|
static const char XMODMAP_EXEC[] = "xmodmap"; |
|
|
|
static bool setxkbmapNotFound = false; |
|
static QString setxkbmapExe; |
|
|
|
static bool xmodmapNotFound = false; |
|
static QString xmodmapExe; |
|
|
|
static const QString COMMAND_OPTIONS_SEPARATOR(QStringLiteral(",")); |
|
|
|
static QString getSetxkbmapExe() |
|
{ |
|
if (setxkbmapNotFound) |
|
return QString(); |
|
|
|
if (setxkbmapExe.isEmpty()) { |
|
setxkbmapExe = QStandardPaths::findExecutable(SETXKBMAP_EXEC); |
|
if (setxkbmapExe.isEmpty()) { |
|
setxkbmapNotFound = true; |
|
qCCritical(KCM_KEYBOARD) << "Can't find" << SETXKBMAP_EXEC << "- keyboard layouts won't be configured"; |
|
return QString(); |
|
} |
|
} |
|
return setxkbmapExe; |
|
} |
|
|
|
static void executeXmodmap(const QString &configFileName) |
|
{ |
|
if (xmodmapNotFound) |
|
return; |
|
|
|
if (QFile(configFileName).exists()) { |
|
if (xmodmapExe.isEmpty()) { |
|
xmodmapExe = QStandardPaths::findExecutable(XMODMAP_EXEC); |
|
if (xmodmapExe.isEmpty()) { |
|
xmodmapNotFound = true; |
|
qCCritical(KCM_KEYBOARD) << "Can't find" << XMODMAP_EXEC << "- xmodmap files won't be run"; |
|
return; |
|
} |
|
} |
|
|
|
qCDebug(KCM_KEYBOARD) << "Executing" << xmodmapExe << configFileName; |
|
const int res = QProcess::execute(xmodmapExe, QStringList{configFileName}); |
|
if (res != 0) { |
|
qCCritical(KCM_KEYBOARD) << "Failed with return code:" << res; |
|
} |
|
} |
|
} |
|
|
|
static void restoreXmodmap() |
|
{ |
|
// TODO: is just home .Xmodmap enough or should system be involved too? |
|
// QString configFileName = QDir("/etc/X11/xinit").filePath(".Xmodmap"); |
|
// executeXmodmap(configFileName); |
|
QString configFileName = QDir::home().filePath(QStringLiteral(".Xmodmap")); |
|
executeXmodmap(configFileName); |
|
} |
|
|
|
// TODO: make private |
|
bool XkbHelper::runConfigLayoutCommand(const QStringList &setxkbmapCommandArguments) |
|
{ |
|
QElapsedTimer timer; |
|
timer.start(); |
|
|
|
const auto setxkbmapExe = getSetxkbmapExe(); |
|
if (setxkbmapExe.isEmpty()) { |
|
return false; |
|
} |
|
|
|
qCDebug(KCM_KEYBOARD) << "Running" << setxkbmapExe << setxkbmapCommandArguments.join(QLatin1Char(' ')); |
|
|
|
const int res = QProcess::execute(setxkbmapExe, setxkbmapCommandArguments); |
|
if (res != 0) { |
|
qCCritical(KCM_KEYBOARD) << "Failed with return code:" << res; |
|
return false; |
|
} |
|
|
|
// restore Xmodmap mapping reset by setxkbmap |
|
qCDebug(KCM_KEYBOARD) << "Executed successfully in " << timer.elapsed() << "ms"; |
|
restoreXmodmap(); |
|
qCDebug(KCM_KEYBOARD) << "\t and with xmodmap" << timer.elapsed() << "ms"; |
|
return true; |
|
} |
|
|
|
bool XkbHelper::initializeKeyboardLayouts(const QList<LayoutUnit> &layoutUnits) |
|
{ |
|
QStringList layouts; |
|
QStringList variants; |
|
for (const auto &layoutUnit : layoutUnits) { |
|
layouts.append(layoutUnit.layout()); |
|
variants.append(layoutUnit.variant()); |
|
} |
|
|
|
QStringList setxkbmapCommandArguments; |
|
setxkbmapCommandArguments.append(QStringLiteral("-layout")); |
|
setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); |
|
if (!variants.join(QString()).isEmpty()) { |
|
setxkbmapCommandArguments.append(QStringLiteral("-variant")); |
|
setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); |
|
} |
|
|
|
return runConfigLayoutCommand(setxkbmapCommandArguments); |
|
} |
|
|
|
bool XkbHelper::initializeKeyboardLayouts(KeyboardConfig &config) |
|
{ |
|
QStringList setxkbmapCommandArguments; |
|
if (!config.keyboardModel().isEmpty()) { |
|
XkbConfig xkbConfig; |
|
X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::MODEL_ONLY); |
|
if (xkbConfig.keyboardModel != config.keyboardModel()) { |
|
setxkbmapCommandArguments.append(QStringLiteral("-model")); |
|
setxkbmapCommandArguments.append(config.keyboardModel()); |
|
} |
|
} |
|
if (config.configureLayouts()) { |
|
QStringList layouts; |
|
QStringList variants; |
|
const QList<LayoutUnit> defaultLayouts = config.getDefaultLayouts(); |
|
for (const auto &layoutUnit : defaultLayouts) { |
|
layouts.append(layoutUnit.layout()); |
|
variants.append(layoutUnit.variant()); |
|
} |
|
|
|
setxkbmapCommandArguments.append(QStringLiteral("-layout")); |
|
setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); |
|
if (!variants.join(QString()).isEmpty()) { |
|
setxkbmapCommandArguments.append(QStringLiteral("-variant")); |
|
setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); |
|
} |
|
} |
|
if (config.resetOldXkbOptions()) { |
|
// Pass -option "" to clear previously set options |
|
setxkbmapCommandArguments.append(QStringLiteral("-option")); |
|
setxkbmapCommandArguments.append(QStringLiteral("")); |
|
} |
|
const QStringList xkbOpts = config.xkbOptions(); |
|
for (const auto &option : xkbOpts) { |
|
setxkbmapCommandArguments.append(QStringLiteral("-option")); |
|
setxkbmapCommandArguments.append(option); |
|
} |
|
|
|
if (!setxkbmapCommandArguments.isEmpty()) { |
|
return runConfigLayoutCommand(setxkbmapCommandArguments); |
|
if (config.configureLayouts()) { |
|
X11Helper::setDefaultLayout(); |
|
} |
|
} |
|
return false; |
|
}
|
|
|