Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions misc/dconfig/org.deepin.dde.treeland.user.seat.json
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,50 @@
"description[zh_CN]": "收到 libinput HOLD BEGIN 事件后等待多少毫秒再触发 hold 手势动作。",
"permissions": "readwrite",
"visibility": "public"
},
"xkbLayout": {
"value": "",
"serial": 0,
"flags": ["global"],
"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\").",
"description[zh_CN]": "XKB 键盘布局。多个布局用逗号分隔,如 \"us\" 或 \"cz,us\"。空字符串表示 XKB 默认值(\"us\")。",
"permissions": "readwrite",
"visibility": "public"
},
"xkbModel": {
"value": "",
"serial": 0,
"flags": ["global"],
"name": "Keyboard Model",
"name[zh_CN]": "键盘型号",
"description": "XKB keyboard model, e.g. \"pc104\" or \"pc105\". Empty string means XKB default.",
"description[zh_CN]": "XKB 键盘型号,如 \"pc104\" 或 \"pc105\"。空字符串表示 XKB 默认值。",
"permissions": "readwrite",
"visibility": "public"
},
"xkbVariant": {
"value": "",
"serial": 0,
"flags": ["global"],
"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).",
"description[zh_CN]": "XKB 键盘变体。用逗号分隔以对应各个布局,如 \"\" 或 \",dvorak\"。空字符串表示无变体(XKB 默认值)。",
"permissions": "readwrite",
"visibility": "public"
},
"xkbOptions": {
"value": "",
"serial": 0,
"flags": ["global"],
"name": "Keyboard Options",
"name[zh_CN]": "键盘选项",
"description": "XKB keyboard options, comma-separated, e.g. \"grp:win_space_toggle\". Empty string means no extra options.",
"description[zh_CN]": "XKB 键盘选项,逗号分隔,如 \"grp:win_space_toggle\"。空字符串表示无额外选项。",
"permissions": "readwrite",
"visibility": "public"
}
}
}
35 changes: 35 additions & 0 deletions src/input/inputmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@

#include "inputmanager.h"
#include "seatuserconfig.hpp"
#include "treelandconfig.hpp"

Check warning on line 6 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "treelandconfig.hpp" not found.
#include "helper.h"

Check warning on line 7 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "helper.h" not found.
#include "inputdevice.h"
#include "common/treelandlogging.h"

Check warning on line 9 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "common/treelandlogging.h" not found.
#include "modules/input-manager/inputmanagerinterfacev1.h"

Check warning on line 10 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "modules/input-manager/inputmanagerinterfacev1.h" not found.
#include "seat/seatsmanager.h"

Check warning on line 11 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "seat/seatsmanager.h" not found.
#include "session/session.h"

Check warning on line 12 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "session/session.h" not found.
#include "xsettings/settingmanager.h"

Check warning on line 13 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "xsettings/settingmanager.h" not found.

#include <libinput.h>

Check warning on line 15 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <libinput.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <xkbcommon/xkbcommon.h>

Check warning on line 16 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <xkbcommon/xkbcommon.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <wlr_all.h>

Check warning on line 18 in src/input/inputmanager.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <wlr_all.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <wbackend.h>
#include <wcursor.h>
Expand Down Expand Up @@ -94,6 +96,13 @@

InputDevice::instance()->setHoldTimeout(m_seatDConfig->touchpadHoldTimeoutMs());

applyXkbConfig();

connect(m_seatDConfig, &SeatUserDConfig::xkbLayoutChanged, this, &InputManager::applyXkbConfig);
connect(m_seatDConfig, &SeatUserDConfig::xkbModelChanged, this, &InputManager::applyXkbConfig);
connect(m_seatDConfig, &SeatUserDConfig::xkbVariantChanged, this, &InputManager::applyXkbConfig);
connect(m_seatDConfig, &SeatUserDConfig::xkbOptionsChanged, this, &InputManager::applyXkbConfig);

auto backend = Helper::instance()->backend();
connect(backend,
&WBackend::inputAdded,
Expand Down Expand Up @@ -571,6 +580,32 @@
}
}

void InputManager::applyXkbConfig()
{
if (!m_seatDConfig || !isSeatDConfigInitialized(m_seatDConfig))
return;

struct xkb_rule_names rules = {};
QByteArray layout = m_seatDConfig->xkbLayout().toUtf8();
QByteArray model = m_seatDConfig->xkbModel().toUtf8();
QByteArray variant = m_seatDConfig->xkbVariant().toUtf8();
QByteArray options = m_seatDConfig->xkbOptions().toUtf8();
rules.layout = layout.constData();
rules.model = model.constData();
rules.variant = variant.constData();
rules.options = options.constData();

auto *seatManager = Helper::instance()->seatManager();
if (seatManager) {
const auto seats = seatManager->seats();
for (WSeat *seat : seats) {
seat->setXkbRuleNames(rules);
}
}

applyNumLockToKeyboards();
}

void InputManager::setNumLockForSeat(WSeat *seat, bool enabled)
{
if (!seat)
Expand Down
1 change: 1 addition & 0 deletions src/input/inputmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ private Q_SLOTS:
private:
bool initializeKeyboardSettings(KeyboardSettingsInterfaceV1 *interface);
void applyNumLockToKeyboards();
void applyXkbConfig();
static void setNumLockForSeat(WSeat *seat, bool enabled);

SeatUserDConfig* m_seatDConfig = nullptr;
Expand Down
72 changes: 66 additions & 6 deletions waylib/src/server/kernel/wseat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ class Q_DECL_HIDDEN WSeatPrivate : public WObjectPrivate
detachInputDevice(device);

destroyKeyboardGroup();

free(const_cast<char*>(xkbRules.rules));
free(const_cast<char*>(xkbRules.layout));
free(const_cast<char*>(xkbRules.model));
free(const_cast<char*>(xkbRules.variant));
free(const_cast<char*>(xkbRules.options));
}

// Release the keyboard group and its WInputDevice wrapper. Shared by
Expand Down Expand Up @@ -367,6 +373,7 @@ class Q_DECL_HIDDEN WSeatPrivate : public WObjectPrivate
void detachInputDevice(WInputDevice *device);
// handle spontaneous & synthetic key event for focusWindow
void handleKeyEvent(QKeyEvent &e);
void applyXkbConfig();

W_DECLARE_PUBLIC(WSeat)

Expand All @@ -387,6 +394,7 @@ class Q_DECL_HIDDEN WSeatPrivate : public WObjectPrivate
qreal lastScale = 1.0;
wlr_keyboard_group *group = nullptr;
WInputDevice *groupkeyboardDevice = nullptr;
struct xkb_rule_names xkbRules = {};

struct EventState {
// Don't use it, its may be a invalid pointer
Expand Down Expand Up @@ -673,11 +681,9 @@ void WSeatPrivate::attachInputDevice(WInputDevice *device)
auto keyboard = wlr_keyboard_from_input_device(device->handle());

if (device == groupkeyboardDevice || device->isVirtual()) {
/* We need to prepare an XKB keymap and assign it to the keyboard.
* This assumes the defaults (e.g. layout = "us"). */
struct xkb_rule_names rules = {};
/* We need to prepare an XKB keymap and assign it to the keyboard. */
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules,
struct xkb_keymap *keymap = xkb_map_new_from_names(context, &xkbRules,
XKB_KEYMAP_COMPILE_NO_FLAGS);
wlr_keyboard_set_keymap(keyboard, keymap);
xkb_keymap_unref(keymap);
Expand All @@ -702,9 +708,8 @@ void WSeatPrivate::attachInputDevice(WInputDevice *device)
qCWarning(lcWlSeat,
"WSeat: group keyboard has no keymap for physical keyboard '%s'",
qPrintable(device->name()));
struct xkb_rule_names rules = {};
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules,
struct xkb_keymap *keymap = xkb_map_new_from_names(context, &xkbRules,
XKB_KEYMAP_COMPILE_NO_FLAGS);
wlr_keyboard_set_keymap(keyboard, keymap);
xkb_keymap_unref(keymap);
Expand Down Expand Up @@ -743,6 +748,42 @@ void WSeatPrivate::detachInputDevice(WInputDevice *device)
Q_ASSERT(ok);
}

void WSeatPrivate::applyXkbConfig()
{
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) {
qCWarning(lcWlSeat) << "Failed to create XKB context";
return;
}

struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, &xkbRules,
XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_context_unref(context);
if (!keymap) {
qCWarning(lcWlSeat) << "Failed to compile XKB keymap from rule names";
return;
}

if (groupkeyboardDevice && groupkeyboardDevice->handle()->type == WLR_INPUT_DEVICE_KEYBOARD) {
auto *keyboard = wlr_keyboard_from_input_device(groupkeyboardDevice->handle());
wlr_keyboard_set_keymap(keyboard, keymap);
}

for (auto *device : std::as_const(deviceList)) {
if (device->type() != WInputDevice::Type::Keyboard)
continue;

if (device->handle()->type != WLR_INPUT_DEVICE_KEYBOARD)
continue;

auto *keyboard = wlr_keyboard_from_input_device(device->handle());
if (keyboard)
wlr_keyboard_set_keymap(keyboard, keymap);
}

xkb_keymap_unref(keymap);
}

WSeat::WSeat(const QString &name)
: QObject(nullptr)
, WObject(*new WSeatPrivate(this, name))
Expand Down Expand Up @@ -1193,6 +1234,25 @@ void WSeat::setKeyboard(WInputDevice *newKeyboard)
Q_EMIT this->keyboardChanged();
}

void WSeat::setXkbRuleNames(const struct xkb_rule_names &rules)
{
W_D(WSeat);

free(const_cast<char*>(d->xkbRules.rules));
free(const_cast<char*>(d->xkbRules.layout));
free(const_cast<char*>(d->xkbRules.model));
free(const_cast<char*>(d->xkbRules.variant));
free(const_cast<char*>(d->xkbRules.options));

d->xkbRules.rules = rules.rules ? strdup(rules.rules) : nullptr;
d->xkbRules.layout = rules.layout ? strdup(rules.layout) : nullptr;
d->xkbRules.model = rules.model ? strdup(rules.model) : nullptr;
d->xkbRules.variant = rules.variant ? strdup(rules.variant) : nullptr;
d->xkbRules.options = rules.options ? strdup(rules.options) : nullptr;

d->applyXkbConfig();
}

bool WSeat::alwaysUpdateHoverTarget() const
{
W_DC(WSeat);
Expand Down
3 changes: 3 additions & 0 deletions waylib/src/server/kernel/wseat.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <QEvent>
#include <QSharedData>
#include <xkbcommon/xkbcommon.h>

Q_MOC_INCLUDE(<wsurface.h>)

Expand Down Expand Up @@ -77,6 +78,8 @@ class WAYLIB_SERVER_EXPORT WSeat : public QObject, public WObject, public WServe
void attachInputDevice(WInputDevice *device);
void detachInputDevice(WInputDevice *device);

void setXkbRuleNames(const struct xkb_rule_names &rules);

// WSurfaceItem is a kind of shellObject
static bool sendEvent(WSurface *target, QObject *shellObject, QObject *eventObject, QInputEvent *event);
static WSeat *get(QInputEvent *event);
Expand Down
Loading