From 812d861307c6970374cbde6c038a1596406e3414 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sat, 12 Aug 2023 21:12:22 +0900 Subject: [PATCH] [keyboard] Add support for setting the layout via locale1 setxkbmap only works on X11/XWayland, and even on XWayland does not correctly change the Wayland keyboard layout. The "modern" way to control the system keyboard layout is via the locale1 DBus interface (or the localectl frontend). On compositors like KWin, this will update the keyboard layout on the fly, which is what we want. Implement support for setting the layout/model configs using locale1. This is enabled by default when Calamares runs under Wayland, and can be controlled via a config setting. Signed-off-by: Hector Martin --- src/modules/keyboard/CMakeLists.txt | 5 +++ src/modules/keyboard/Config.cpp | 61 +++++++++++++++++++++++++++- src/modules/keyboard/Config.h | 2 + src/modules/keyboard/keyboard.conf | 6 +++ src/modules/keyboardq/CMakeLists.txt | 4 ++ 5 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/modules/keyboard/CMakeLists.txt b/src/modules/keyboard/CMakeLists.txt index a2e09dc41..10868a269 100644 --- a/src/modules/keyboard/CMakeLists.txt +++ b/src/modules/keyboard/CMakeLists.txt @@ -3,6 +3,9 @@ # SPDX-FileCopyrightText: 2020 Adriaan de Groot # SPDX-License-Identifier: BSD-2-Clause # + +find_package(Qt5 ${QT_VERSION} CONFIG REQUIRED Core DBus) + calamares_add_plugin(keyboard TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO @@ -19,6 +22,8 @@ calamares_add_plugin(keyboard RESOURCES keyboard.qrc SHARED_LIB + LINK_LIBRARIES + Qt5::DBus ) calamares_add_test(keyboardtest SOURCES Tests.cpp SetKeyboardLayoutJob.cpp RESOURCES keyboard.qrc) diff --git a/src/modules/keyboard/Config.cpp b/src/modules/keyboard/Config.cpp index e7ffc6555..c2f27982c 100644 --- a/src/modules/keyboard/Config.cpp +++ b/src/modules/keyboard/Config.cpp @@ -23,9 +23,14 @@ #include "utils/Variant.h" #include +#include #include #include +#include +#include +#include + /* Returns stringlist with suitable setxkbmap command-line arguments * to set the given @p model. */ @@ -163,7 +168,14 @@ Config::Config( QObject* parent ) { // Set Xorg keyboard model m_selectedModel = m_keyboardModelsModel->key( index ); - QProcess::execute( "setxkbmap", xkbmap_model_args( m_selectedModel ) ); + if ( m_useLocale1 ) + { + locale1Apply(); + } + else + { + QProcess::execute( "setxkbmap", xkbmap_model_args( m_selectedModel ) ); + } emit prettyStatusChanged(); } ); @@ -201,12 +213,55 @@ Config::xkbChanged( int index ) m_setxkbmapTimer.disconnect( this ); } - connect( &m_setxkbmapTimer, &QTimer::timeout, this, &Config::xkbApply ); + if ( m_useLocale1 ) + { + connect( &m_setxkbmapTimer, &QTimer::timeout, this, &Config::locale1Apply ); + } + else + { + connect( &m_setxkbmapTimer, &QTimer::timeout, this, &Config::xkbApply ); + } m_setxkbmapTimer.start( QApplication::keyboardInputInterval() ); emit prettyStatusChanged(); } +void +Config::locale1Apply() +{ + m_additionalLayoutInfo = getAdditionalLayoutInfo( m_selectedLayout ); + + QString layout = m_selectedLayout; + QString variant = m_selectedVariant; + QString option; + + if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() ) + { + layout = m_additionalLayoutInfo.additionalLayout + "," + layout; + variant = m_additionalLayoutInfo.additionalVariant + "," + layout; + option = m_additionalLayoutInfo.groupSwitcher; + } + + QDBusInterface locale1( "org.freedesktop.locale1", + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + QDBusConnection::systemBus() ); + if ( !locale1.isValid() ) + { + cWarning() << "Interface" << locale1.interface() << "is not valid."; + return; + } + + // Using convert=true, this also updates the VConsole config + { + QDBusReply< void > r = locale1.call( "SetX11Keyboard", layout, m_selectedModel, variant, option, true, false ); + if ( !r.isValid() ) + { + cWarning() << "Could not set keyboard config through org.freedesktop.locale1.X11Keyboard." << r.error(); + } + } +} + void Config::xkbApply() { @@ -561,6 +616,7 @@ void Config::setConfigurationMap( const QVariantMap& configurationMap ) { using namespace CalamaresUtils; + bool isX11 = QGuiApplication::platformName() == "xcb"; const auto xorgConfDefault = QStringLiteral( "00-keyboard.conf" ); m_xOrgConfFileName = getString( configurationMap, "xOrgConfFileName", xorgConfDefault ); @@ -570,6 +626,7 @@ Config::setConfigurationMap( const QVariantMap& configurationMap ) } m_convertedKeymapPath = getString( configurationMap, "convertedKeymapPath" ); m_writeEtcDefaultKeyboard = getBool( configurationMap, "writeEtcDefaultKeyboard", true ); + m_useLocale1 = getBool( configurationMap, "useLocale1", !isX11 ); } void diff --git a/src/modules/keyboard/Config.h b/src/modules/keyboard/Config.h index 436ead4b5..e5bd7cb8b 100644 --- a/src/modules/keyboard/Config.h +++ b/src/modules/keyboard/Config.h @@ -89,6 +89,7 @@ private: */ void xkbChanged( int index ); void xkbApply(); + void locale1Apply(); KeyboardModelsModel* m_keyboardModelsModel; KeyboardLayoutModel* m_keyboardLayoutsModel; @@ -107,6 +108,7 @@ private: QString m_xOrgConfFileName; QString m_convertedKeymapPath; bool m_writeEtcDefaultKeyboard = true; + bool m_useLocale1; // The state determines whether we guess settings or preserve them: // - Initial -> Guessing diff --git a/src/modules/keyboard/keyboard.conf b/src/modules/keyboard/keyboard.conf index 3b2f3a312..8d623b42e 100644 --- a/src/modules/keyboard/keyboard.conf +++ b/src/modules/keyboard/keyboard.conf @@ -21,3 +21,9 @@ convertedKeymapPath: "/lib/kbd/keymaps/xkb" # found on Debian-related systems. # Defaults to true if nothing is set. #writeEtcDefaultKeyboard: true + +# Use the Locale1 service instead of directly managing configuration files. +# This is the modern mechanism for configuring the systemwide keyboard layout, +# and works on Wayland compositors to set the current layout. +# Defaults to false on X11 and true otherwise. +#useLocale1: true diff --git a/src/modules/keyboardq/CMakeLists.txt b/src/modules/keyboardq/CMakeLists.txt index 9c7922d86..afd8d4aad 100644 --- a/src/modules/keyboardq/CMakeLists.txt +++ b/src/modules/keyboardq/CMakeLists.txt @@ -8,6 +8,8 @@ if(NOT WITH_QML) return() endif() +find_package(Qt5 ${QT_VERSION} CONFIG REQUIRED Core DBus) + set(_keyboard ${CMAKE_CURRENT_SOURCE_DIR}/../keyboard) include_directories(${_keyboard}) @@ -24,4 +26,6 @@ calamares_add_plugin(keyboardq RESOURCES keyboardq.qrc SHARED_LIB + LINK_LIBRARIES + Qt5::DBus )