From 5dab7672a54f98e5f588d3bc2690444c26af6f6f Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Mon, 21 Sep 2026 15:45:33 +0800 Subject: [PATCH 1/2] feat: add XKB settings to input manager Expose version 2 of treeland_input_manager_v1 and support configuring XKB layout, model, variant, and options as a single rules snapshot. Report the stored XKB rules when keyboard settings are created, persist applied protocol changes to seat DConfig, and apply them directly to the target seat. Normalize nullable protocol strings to empty values. Log: add XKB settings to input manager PMS: BUG-377251 Influence: Compatible change --- .../org.deepin.dde.treeland.user.seat.json | 8 +- src/input/inputmanager.cpp | 52 +++++++++---- src/input/inputmanager.h | 5 ++ .../input-manager/inputmanagerinterfacev1.cpp | 74 +++++++++++++++++++ .../input-manager/inputmanagerinterfacev1.h | 14 +++- 5 files changed, 135 insertions(+), 18 deletions(-) diff --git a/misc/dconfig/org.deepin.dde.treeland.user.seat.json b/misc/dconfig/org.deepin.dde.treeland.user.seat.json index e4414d10c6..b1f3157554 100644 --- a/misc/dconfig/org.deepin.dde.treeland.user.seat.json +++ b/misc/dconfig/org.deepin.dde.treeland.user.seat.json @@ -159,7 +159,7 @@ "xkbLayout": { "value": "", "serial": 0, - "flags": ["global"], + "flags": [], "name": "Keyboard Layout", "name[zh_CN]": "键盘布局", "description": "XKB keyboard layout(s). Comma-separated list for multiple layouts, e.g. \"us\" or \"cz,us\". Empty string means XKB default (\"us\").", @@ -170,7 +170,7 @@ "xkbModel": { "value": "", "serial": 0, - "flags": ["global"], + "flags": [], "name": "Keyboard Model", "name[zh_CN]": "键盘型号", "description": "XKB keyboard model, e.g. \"pc104\" or \"pc105\". Empty string means XKB default.", @@ -181,7 +181,7 @@ "xkbVariant": { "value": "", "serial": 0, - "flags": ["global"], + "flags": [], "name": "Keyboard Variant", "name[zh_CN]": "键盘变体", "description": "XKB keyboard variant(s). Comma-separated list matching the layouts, e.g. \"\" or \",dvorak\". Empty string means no variant (XKB default).", @@ -192,7 +192,7 @@ "xkbOptions": { "value": "", "serial": 0, - "flags": ["global"], + "flags": [], "name": "Keyboard Options", "name[zh_CN]": "键盘选项", "description": "XKB keyboard options, comma-separated, e.g. \"grp:win_space_toggle\". Empty string means no extra options.", diff --git a/src/input/inputmanager.cpp b/src/input/inputmanager.cpp index 0fc661ae90..edce3ed11f 100644 --- a/src/input/inputmanager.cpp +++ b/src/input/inputmanager.cpp @@ -102,15 +102,6 @@ void InputManager::setupSeat(WSeat *seat) applyXkbConfigForSeat(seat); - connect(config, &SeatUserDConfig::xkbLayoutChanged, this, - [this, seat] { applyXkbConfigForSeat(seat); }); - connect(config, &SeatUserDConfig::xkbModelChanged, this, - [this, seat] { applyXkbConfigForSeat(seat); }); - connect(config, &SeatUserDConfig::xkbVariantChanged, this, - [this, seat] { applyXkbConfigForSeat(seat); }); - connect(config, &SeatUserDConfig::xkbOptionsChanged, this, - [this, seat] { applyXkbConfigForSeat(seat); }); - const auto devices = seat->deviceList(); for (WInputDevice *device : devices) onInputAssigned(device); @@ -177,6 +168,11 @@ bool InputManager::initializeKeyboardSettings(KeyboardSettingsInterfaceV1 *inter interface->sendFeature(features, true); interface->sendNumLock(globalConfig->keyboardNumLock(), true); interface->sendRepeat(seatConfig->keyboardRate(), seatConfig->keyboardDelay(), true); + interface->sendXkbRules(seatConfig->xkbLayout(), + seatConfig->xkbModel(), + seatConfig->xkbVariant(), + seatConfig->xkbOptions(), + true); interface->sendDone(); connect(interface, @@ -483,6 +479,13 @@ void InputManager::onKeyboardSettingsApplied(KeyboardSettingsInterfaceV1::Change seatConfig->setKeyboardRate(interface->repeatRate()); } + if (changes.testFlag(KeyboardSettingsInterfaceV1::XkbRulesChanged)) { + seatConfig->setXkbLayout(interface->xkbLayout()); + seatConfig->setXkbModel(interface->xkbModel()); + seatConfig->setXkbVariant(interface->xkbVariant()); + seatConfig->setXkbOptions(interface->xkbOptions()); + } + auto *keyboardDevice = interface->wSeat()->keyboardGroupKeyboard(); if (keyboardDevice) { if (keyboardDevice->handle()->type == WLR_INPUT_DEVICE_KEYBOARD) { @@ -495,6 +498,14 @@ void InputManager::onKeyboardSettingsApplied(KeyboardSettingsInterfaceV1::Change if (changes.testFlag(KeyboardSettingsInterfaceV1::NumLockChanged)) setNumLockForSeat(interface->wSeat(), interface->numLock()); + + if (changes.testFlag(KeyboardSettingsInterfaceV1::XkbRulesChanged)) { + applyXkbConfig(interface->wSeat(), + interface->xkbLayout(), + interface->xkbModel(), + interface->xkbVariant(), + interface->xkbOptions()); + } } void InputManager::applyNumLockToKeyboards() @@ -521,11 +532,26 @@ void InputManager::applyXkbConfigForSeat(WSeat *seat) auto *seatConfig = seatUserConfig(seat); + applyXkbConfig(seat, + seatConfig->xkbLayout(), + seatConfig->xkbModel(), + seatConfig->xkbVariant(), + seatConfig->xkbOptions()); +} + +void InputManager::applyXkbConfig(WSeat *seat, + const QString &layoutName, + const QString &modelName, + const QString &variantName, + const QString &optionsName) +{ + Q_ASSERT(seat); + struct xkb_rule_names rules = {}; - QByteArray layout = seatConfig->xkbLayout().toUtf8(); - QByteArray model = seatConfig->xkbModel().toUtf8(); - QByteArray variant = seatConfig->xkbVariant().toUtf8(); - QByteArray options = seatConfig->xkbOptions().toUtf8(); + QByteArray layout = layoutName.toUtf8(); + QByteArray model = modelName.toUtf8(); + QByteArray variant = variantName.toUtf8(); + QByteArray options = optionsName.toUtf8(); rules.layout = layout.constData(); rules.model = model.constData(); rules.variant = variant.constData(); diff --git a/src/input/inputmanager.h b/src/input/inputmanager.h index 056033f5c0..b386166638 100644 --- a/src/input/inputmanager.h +++ b/src/input/inputmanager.h @@ -46,6 +46,11 @@ private Q_SLOTS: void setupSeat(WSeat *seat); void applyNumLockToKeyboards(); void applyXkbConfigForSeat(WSeat *seat); + void applyXkbConfig(WSeat *seat, + const QString &layout, + const QString &model, + const QString &variant, + const QString &options); static void setNumLockForSeat(WSeat *seat, bool enabled); QString m_userName; diff --git a/src/modules/input-manager/inputmanagerinterfacev1.cpp b/src/modules/input-manager/inputmanagerinterfacev1.cpp index dc295a9870..c6a0096776 100644 --- a/src/modules/input-manager/inputmanagerinterfacev1.cpp +++ b/src/modules/input-manager/inputmanagerinterfacev1.cpp @@ -20,6 +20,11 @@ static QList s_mouseSettings; static QList s_touchpadSettings; static QList s_keyboardSettings; +static QString normalizeNullableXkbString(const QString &value) +{ + return value.isNull() ? QStringLiteral("") : value; +} + class TreelandInputManagerInterfaceV1Private : public QtWaylandServer::treeland_input_manager_v1 { public: @@ -854,6 +859,10 @@ class KeyboardSettingsInterfaceV1Private : public QtWaylandServer::treeland_keyb int32_t repeatRate = 0; int32_t repeatDelay = 0; bool numLock = false; + QString xkbLayout; + QString xkbModel; + QString xkbVariant; + QString xkbOptions; protected: void destroy_resource(Resource *resource) override; @@ -861,6 +870,11 @@ class KeyboardSettingsInterfaceV1Private : public QtWaylandServer::treeland_keyb void set_repeat(Resource *resource, int32_t rate, int32_t delay) override; void set_num_lock(Resource *resource, uint32_t state) override; void apply(Resource *resource) override; + void set_xkb_rules(Resource *resource, + const QString &layout, + const QString &model, + const QString &variant, + const QString &options) override; }; KeyboardSettingsInterfaceV1Private::KeyboardSettingsInterfaceV1Private(KeyboardSettingsInterfaceV1 *_q, @@ -914,6 +928,19 @@ void KeyboardSettingsInterfaceV1Private::apply([[maybe_unused]] Resource *resour pendingChanges = KeyboardSettingsInterfaceV1::NoChange; } +void KeyboardSettingsInterfaceV1Private::set_xkb_rules([[maybe_unused]] Resource *resource, + const QString &layout, + const QString &model, + const QString &variant, + const QString &options) +{ + xkbLayout = normalizeNullableXkbString(layout); + xkbModel = normalizeNullableXkbString(model); + xkbVariant = normalizeNullableXkbString(variant); + xkbOptions = normalizeNullableXkbString(options); + pendingChanges |= KeyboardSettingsInterfaceV1::XkbRulesChanged; +} + KeyboardSettingsInterfaceV1::KeyboardSettingsInterfaceV1(wl_resource *resource, wl_resource *seat, QObject *parent) @@ -957,6 +984,33 @@ void KeyboardSettingsInterfaceV1::sendNumLock(bool enabled, bool force) d->numLock = enabled; } +void KeyboardSettingsInterfaceV1::sendXkbRules(const QString &layout, + const QString &model, + const QString &variant, + const QString &options, + bool force) +{ + const QString normalizedLayout = normalizeNullableXkbString(layout); + const QString normalizedModel = normalizeNullableXkbString(model); + const QString normalizedVariant = normalizeNullableXkbString(variant); + const QString normalizedOptions = normalizeNullableXkbString(options); + + if (d->resource()->version() < XkbVersion + || (!force + && d->xkbLayout == normalizedLayout + && d->xkbModel == normalizedModel + && d->xkbVariant == normalizedVariant + && d->xkbOptions == normalizedOptions)) { + return; + } + + d->send_xkb_rules(normalizedLayout, normalizedModel, normalizedVariant, normalizedOptions); + d->xkbLayout = normalizedLayout; + d->xkbModel = normalizedModel; + d->xkbVariant = normalizedVariant; + d->xkbOptions = normalizedOptions; +} + void KeyboardSettingsInterfaceV1::sendFailed() { d->send_failed(); @@ -982,6 +1036,26 @@ bool KeyboardSettingsInterfaceV1::numLock() const return d->numLock; } +const QString &KeyboardSettingsInterfaceV1::xkbLayout() const +{ + return d->xkbLayout; +} + +const QString &KeyboardSettingsInterfaceV1::xkbModel() const +{ + return d->xkbModel; +} + +const QString &KeyboardSettingsInterfaceV1::xkbVariant() const +{ + return d->xkbVariant; +} + +const QString &KeyboardSettingsInterfaceV1::xkbOptions() const +{ + return d->xkbOptions; +} + wl_resource *KeyboardSettingsInterfaceV1::seat() const { return d->seat; diff --git a/src/modules/input-manager/inputmanagerinterfacev1.h b/src/modules/input-manager/inputmanagerinterfacev1.h index a2b34a173d..b6b45631be 100644 --- a/src/modules/input-manager/inputmanagerinterfacev1.h +++ b/src/modules/input-manager/inputmanagerinterfacev1.h @@ -40,7 +40,7 @@ class TreelandInputManagerInterfaceV1 : public QObject, public WServerInterface QByteArrayView interfaceName() const override; - static constexpr int InterfaceVersion = 1; + static constexpr int InterfaceVersion = 2; Q_SIGNALS: void mouseSettingsCreated(MouseSettingsInterfaceV1 *interface); @@ -212,6 +212,8 @@ class KeyboardSettingsInterfaceV1 : public QObject { Q_OBJECT public: + static constexpr int XkbVersion = 2; + ~KeyboardSettingsInterfaceV1() override; enum FeatureFlag { @@ -225,6 +227,7 @@ class KeyboardSettingsInterfaceV1 : public QObject NoChange = 0, RepeatChanged = 1 << 0, NumLockChanged = 1 << 1, + XkbRulesChanged = 1 << 2, }; Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag) Q_FLAG(ChangeFlags) @@ -232,12 +235,21 @@ class KeyboardSettingsInterfaceV1 : public QObject void sendFeature(FeatureFlags features, bool force = false); void sendRepeat(int32_t rate, int32_t delay, bool force = false); void sendNumLock(bool enabled, bool force = false); + void sendXkbRules(const QString &layout, + const QString &model, + const QString &variant, + const QString &options, + bool force = false); void sendFailed(); void sendDone(); int32_t repeatRate() const; int32_t repeatDelay() const; bool numLock() const; + const QString &xkbLayout() const; + const QString &xkbModel() const; + const QString &xkbVariant() const; + const QString &xkbOptions() const; wl_resource *seat() const; WSeat *wSeat() const; From 6345058ec15352a5b666399477c7387f9f0382be Mon Sep 17 00:00:00 2001 From: YaoBing Xiao Date: Mon, 21 Sep 2026 16:06:41 +0800 Subject: [PATCH 2/2] feat: add XKB rules test to input manager example Bind treeland_input_manager_v1 at version 2 and handle the xkb_rules state event in the input manager example client. Add command-line options for XKB layout, model, variant, and options. Send them as a single rules snapshot through set_xkb_rules and apply the configuration to exercise the version 2 protocol path. Log: add XKB rules test to input manager example PMS: BUG-377251 Influence: Compatible change --- .../test_input_manager/inputmanagerclient.cpp | 27 +++++++++++++ .../test_input_manager/inputmanagerclient.h | 10 ++++- examples/test_input_manager/main.cpp | 39 +++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/examples/test_input_manager/inputmanagerclient.cpp b/examples/test_input_manager/inputmanagerclient.cpp index 185bbeabe5..9ca92cc327 100644 --- a/examples/test_input_manager/inputmanagerclient.cpp +++ b/examples/test_input_manager/inputmanagerclient.cpp @@ -237,6 +237,20 @@ void TreelandKeyboardSettingsV1::configureAndApply(int32_t rate, int32_t delay) << "delay:" << delay; } +void TreelandKeyboardSettingsV1::configureXkbRulesAndApply(const QString &layout, + const QString &model, + const QString &variant, + const QString &options) +{ + set_xkb_rules(layout, model, variant, options); + apply(); + qWarning() << "Keyboard XKB rules applied:" + << "layout:" << layout + << "model:" << model + << "variant:" << variant + << "options:" << options; +} + void TreelandKeyboardSettingsV1::treeland_keyboard_settings_v1_repeat(int32_t rate, int32_t delay) { qWarning() << "repeat rate:" << rate << "delay:" << delay; @@ -257,3 +271,16 @@ void TreelandKeyboardSettingsV1::treeland_keyboard_settings_v1_done() qWarning() << "keyboard settings: done"; qWarning() << ""; } + +void TreelandKeyboardSettingsV1::treeland_keyboard_settings_v1_xkb_rules( + const QString &layout, + const QString &model, + const QString &variant, + const QString &options) +{ + qWarning() << "xkb_rules:" + << "layout:" << layout + << "model:" << model + << "variant:" << variant + << "options:" << options; +} diff --git a/examples/test_input_manager/inputmanagerclient.h b/examples/test_input_manager/inputmanagerclient.h index 0aea47cda9..2030a1c640 100644 --- a/examples/test_input_manager/inputmanagerclient.h +++ b/examples/test_input_manager/inputmanagerclient.h @@ -15,7 +15,7 @@ class TreelandInputManagerV1 { Q_OBJECT public: - static constexpr int InterfaceVersion = 1; + static constexpr int InterfaceVersion = 2; explicit TreelandInputManagerV1(); ~TreelandInputManagerV1() override; @@ -75,6 +75,10 @@ class TreelandKeyboardSettingsV1 bool hasFeature(uint32_t flag) const; void configureAndApply(int32_t rate, int32_t delay); + void configureXkbRulesAndApply(const QString &layout, + const QString &model, + const QString &variant, + const QString &options); protected: void treeland_keyboard_settings_v1_feature(uint32_t feature) override; @@ -82,6 +86,10 @@ class TreelandKeyboardSettingsV1 void treeland_keyboard_settings_v1_num_lock(uint32_t state) override; void treeland_keyboard_settings_v1_failed() override; void treeland_keyboard_settings_v1_done() override; + void treeland_keyboard_settings_v1_xkb_rules(const QString &layout, + const QString &model, + const QString &variant, + const QString &options) override; private: uint32_t m_features = 0; diff --git a/examples/test_input_manager/main.cpp b/examples/test_input_manager/main.cpp index 381f969f21..d0f231caf8 100644 --- a/examples/test_input_manager/main.cpp +++ b/examples/test_input_manager/main.cpp @@ -264,6 +264,34 @@ int main(int argc, char *argv[]) ); parser.addOption(keyboardNumLockOption); + QCommandLineOption keyboardXkbLayoutOption( + QStringLiteral("keyboard-xkb-layout"), + QStringLiteral("Comma-separated XKB keyboard layouts (e.g. us or cz,us)."), + QStringLiteral("layout") + ); + parser.addOption(keyboardXkbLayoutOption); + + QCommandLineOption keyboardXkbModelOption( + QStringLiteral("keyboard-xkb-model"), + QStringLiteral("XKB keyboard model (e.g. pc104 or pc105)."), + QStringLiteral("model") + ); + parser.addOption(keyboardXkbModelOption); + + QCommandLineOption keyboardXkbVariantOption( + QStringLiteral("keyboard-xkb-variant"), + QStringLiteral("Comma-separated XKB keyboard variants (e.g. ,dvorak)."), + QStringLiteral("variant") + ); + parser.addOption(keyboardXkbVariantOption); + + QCommandLineOption keyboardXkbOptionsOption( + QStringLiteral("keyboard-xkb-options"), + QStringLiteral("Comma-separated XKB keyboard options (e.g. grp:win_space_toggle)."), + QStringLiteral("options") + ); + parser.addOption(keyboardXkbOptionsOption); + parser.process(app); auto *manager = new TreelandInputManagerV1; @@ -334,6 +362,17 @@ int main(int argc, char *argv[]) keyboardSettings->apply(); qDebug() << "Keyboard num lock applied:" << (state ? "on" : "off"); } + + if (parser.isSet("keyboard-xkb-layout") + || parser.isSet("keyboard-xkb-model") + || parser.isSet("keyboard-xkb-variant") + || parser.isSet("keyboard-xkb-options")) { + keyboardSettings->configureXkbRulesAndApply( + parser.value("keyboard-xkb-layout"), + parser.value("keyboard-xkb-model"), + parser.value("keyboard-xkb-variant"), + parser.value("keyboard-xkb-options")); + } } else { qWarning() << "Failed to get keyboard settings"; }