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"; } 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;