Skip to content

Commit 3a59e9d

Browse files
deepin-wmdeepin-bot[bot]
authored andcommitted
fix: listen keyboard-state-notify for NumLock sync
1. Add treeland-keyboard-state-notify-unstable-v1.xml protocol generation 2. Add KeyboardStateNotify class to wrap the keyboard state notify protocol 3. Add KeyboardStateNotify member to KeyboardWaylandProxy 4. Connect numLockChanged signal from KeyboardStateNotify in proxy Log: Fix NumLock state out of sync in Treeland mode Influence: 1. Test NumLock toggle via physical key and verify control center UI syncs 2. Test NumLock toggle via control center switch and verify keyboard LED syncs 3. Test NumLock state after reconnecting USB keyboard fix: 监听 keyboard-state-notify 协议解决 NumLock 状态不同步 1. 添加 treeland-keyboard-state-notify-unstable-v1.xml 协议生成 2. 添加 KeyboardStateNotify 类封装键盘状态通知协议 3. 在 KeyboardWaylandProxy 中添加 KeyboardStateNotify 成员 4. 在代理中连接 KeyboardStateNotify 的 numLockChanged 信号 Log: 修复 Treeland 模式下 NumLock 状态不同步问题 Influence: 1. 测试通过物理按键切换 NumLock,验证控制中心 UI 同步更新 2. 测试通过控制中心开关切换 NumLock,验证键盘 LED 同步 3. 测试重新连接 USB 键盘后 NumLock 状态正确显示 PMS: BUG-367621
1 parent 4193ec2 commit 3a59e9d

8 files changed

Lines changed: 234 additions & 1 deletion

File tree

src/plugin-keyboard/operation/ikeyboarddeviceproxy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class IKeyboardDeviceProxy
1313
virtual ~IKeyboardDeviceProxy() = default;
1414

1515
virtual void active() = 0;
16+
virtual void deactive() = 0;
1617

1718
virtual uint repeatDelay() const = 0;
1819
virtual uint repeatInterval() const = 0;

src/plugin-keyboard/operation/keyboarddbusproxy.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class KeyboardDBusProxy : public QObject, public DCC_NAMESPACE::IKeyboardDeviceP
100100
public:
101101
explicit KeyboardDBusProxy(QObject *parent = nullptr);
102102
void active() override {}
103+
void deactive() override {}
103104

104105
//Keyboard
105106
Q_PROPERTY(bool CapslockToggle READ capslockToggle WRITE setCapslockToggle NOTIFY CapslockToggleChanged)

src/plugin-keyboard/operation/keyboardwaylandproxy.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "keyboardwaylandproxy.h"
55

66
#include "treelandinputmanager.h"
7+
#include "keyboardstatenotify.h"
78

89
#include <QLoggingCategory>
910

@@ -39,6 +40,23 @@ void KeyboardWaylandProxy::active()
3940
qCDebug(lcKeyboardWaylandProxy) << "Keyboard not yet available, waiting for signal";
4041
}
4142
Q_EMIT KeyboardAvailableChanged(m_inputManager->keyboardAvailable());
43+
44+
if (!m_keyboardStateNotify) {
45+
m_keyboardStateNotify = new KeyboardStateNotify(this);
46+
connect(m_keyboardStateNotify, &KeyboardStateNotify::numLockChanged, this,
47+
[this](bool on) {
48+
qCDebug(lcKeyboardWaylandProxy) << "numLockChanged (global state notify):" << on;
49+
Q_EMIT NumLockStateChanged(on ? 1 : 0);
50+
});
51+
qCDebug(lcKeyboardWaylandProxy) << "KeyboardStateNotify initialized";
52+
}
53+
}
54+
55+
void KeyboardWaylandProxy::deactive()
56+
{
57+
qCDebug(lcKeyboardWaylandProxy) << "KeyboardWaylandProxy::deactive()";
58+
delete m_keyboardStateNotify;
59+
m_keyboardStateNotify = nullptr;
4260
}
4361

4462
void KeyboardWaylandProxy::connectKeyboardSettings(TreelandKeyboardSettings *kbd)

src/plugin-keyboard/operation/keyboardwaylandproxy.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace DCC_NAMESPACE {
1313

1414
class TreelandInputManager;
1515
class TreelandKeyboardSettings;
16+
class KeyboardStateNotify;
1617

1718
/**
1819
* @brief 封装 treeland 输入管理协议的键盘代理类,对外提供与 KeyboardDBusProxy 相同的信号/槽接口,
@@ -32,6 +33,7 @@ class KeyboardWaylandProxy : public QObject, public IKeyboardDeviceProxy
3233

3334
/** 初始化并连接 TreelandInputManager 信号,发射当前初始状态 */
3435
void active() override;
36+
void deactive() override;
3537
bool keyboardAvailable() const;
3638

3739
// ---- 同步读取当前缓存值(与 KeyboardDBusProxy 接口保持兼容)----
@@ -76,7 +78,7 @@ public Q_SLOTS:
7678

7779
TreelandInputManager *m_inputManager = nullptr;
7880
QPointer<TreelandKeyboardSettings> m_keyboardSettings;
81+
KeyboardStateNotify *m_keyboardStateNotify = nullptr;
7982
};
8083

8184
} // namespace DCC_NAMESPACE
82-

src/plugin-keyboard/operation/keyboardwork.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ void KeyboardWorker::active()
217217
void KeyboardWorker::deactive()
218218
{
219219
m_keyboardDBusProxy->blockSignals(true);
220+
if (m_deviceProxy)
221+
m_deviceProxy->deactive();
220222
}
221223

222224
void KeyboardWorker::refreshKeyboard()

src/shared-utils/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ if (Enable_TreelandSupport)
3737
qt6_generate_wayland_protocol_client_sources(dcc-shared-utils
3838
FILES
3939
${TREELAND_PROTOCOLS_DATA_DIR}/treeland-input-manager-unstable-v1.xml
40+
${TREELAND_PROTOCOLS_DATA_DIR}/treeland-keyboard-state-notify-unstable-v1.xml
4041
)
4142

4243
target_include_directories(dcc-shared-utils PUBLIC
@@ -46,6 +47,8 @@ if (Enable_TreelandSupport)
4647
target_sources(dcc-shared-utils PRIVATE
4748
treelandinputmanager.h
4849
treelandinputmanager.cpp
50+
keyboardstatenotify.h
51+
keyboardstatenotify.cpp
4952
)
5053

5154
if(${QT_NS}_VERSION VERSION_GREATER_EQUAL 6.10)
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
2+
//
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
#include "keyboardstatenotify.h"
6+
7+
#include <QGuiApplication>
8+
#include <QLoggingCategory>
9+
#include <wayland-client.h>
10+
11+
namespace DCC_NAMESPACE {
12+
13+
Q_LOGGING_CATEGORY(lcKbdStateNotify, "dde.dcc.keyboard.statenotify")
14+
15+
// ---------------------------------------------------------------------------
16+
// Watcher
17+
// ---------------------------------------------------------------------------
18+
19+
KeyboardStateNotify::Watcher::Watcher(KeyboardStateNotify *parent,
20+
struct ::treeland_keyboard_state_watcher_v1 *obj)
21+
: QObject(parent)
22+
, QtWayland::treeland_keyboard_state_watcher_v1(obj)
23+
{
24+
qCDebug(lcKbdStateNotify) << "Watcher created, configuring to watch num_lock with all flags";
25+
26+
// Watch num_lock modifier
27+
set_modifiers(modifier_num_lock);
28+
29+
// Receive both locked and unlocked events
30+
set_flags(watch_flag_locked | watch_flag_unlocked);
31+
32+
apply();
33+
}
34+
35+
KeyboardStateNotify::Watcher::~Watcher()
36+
{
37+
if (isInitialized())
38+
destroy();
39+
}
40+
41+
void KeyboardStateNotify::Watcher::treeland_keyboard_state_watcher_v1_current_state(
42+
uint32_t modifier, uint32_t state)
43+
{
44+
qCDebug(lcKbdStateNotify) << "current_state: modifier=" << modifier << "state=" << state;
45+
46+
if (modifier == modifier_num_lock) {
47+
bool on = (state == modifier_state_locked);
48+
Q_EMIT numLockChanged(on);
49+
}
50+
}
51+
52+
void KeyboardStateNotify::Watcher::treeland_keyboard_state_watcher_v1_state_changed(
53+
uint32_t modifier, uint32_t state)
54+
{
55+
qCDebug(lcKbdStateNotify) << "state_changed: modifier=" << modifier << "state=" << state;
56+
57+
if (modifier == modifier_num_lock) {
58+
bool on = (state == modifier_state_locked);
59+
Q_EMIT numLockChanged(on);
60+
}
61+
}
62+
63+
// ---------------------------------------------------------------------------
64+
// KeyboardStateNotify
65+
// ---------------------------------------------------------------------------
66+
67+
KeyboardStateNotify::KeyboardStateNotify(QObject *parent)
68+
: QWaylandClientExtensionTemplate<KeyboardStateNotify>(1)
69+
, QtWayland::treeland_keyboard_state_notify_manager_v1()
70+
{
71+
setParent(parent);
72+
73+
qCDebug(lcKbdStateNotify) << "KeyboardStateNotify initializing";
74+
75+
connect(this, &QWaylandClientExtension::activeChanged, this, [this]() {
76+
const bool avail = isActive();
77+
qCDebug(lcKbdStateNotify) << "active changed:" << avail;
78+
79+
if (m_available != avail) {
80+
m_available = avail;
81+
Q_EMIT availableChanged(avail);
82+
}
83+
84+
if (avail) {
85+
auto *waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
86+
if (waylandApp) {
87+
createWatcher(nullptr);
88+
}
89+
} else {
90+
delete m_watcher;
91+
m_watcher = nullptr;
92+
}
93+
});
94+
95+
96+
}
97+
98+
KeyboardStateNotify::~KeyboardStateNotify()
99+
{
100+
delete m_watcher;
101+
m_watcher = nullptr;
102+
}
103+
104+
bool KeyboardStateNotify::available() const
105+
{
106+
return m_available;
107+
}
108+
109+
void KeyboardStateNotify::createWatcher(wl_seat *seat)
110+
{
111+
if (m_watcher) {
112+
delete m_watcher;
113+
m_watcher = nullptr;
114+
}
115+
116+
if (!isActive() || !QtWayland::treeland_keyboard_state_notify_manager_v1::isInitialized())
117+
return;
118+
119+
// Pass null seat to monitor all seats
120+
auto *watcherObj = get_keyboard_state_watcher(seat);
121+
m_watcher = new Watcher(this, watcherObj);
122+
123+
connect(m_watcher, &Watcher::numLockChanged, this, &KeyboardStateNotify::numLockChanged);
124+
125+
// Flush the Wayland display to ensure the request is sent
126+
auto *waylandApp = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
127+
if (waylandApp && waylandApp->display())
128+
wl_display_flush(waylandApp->display());
129+
130+
qCDebug(lcKbdStateNotify) << "Watcher created and configured";
131+
}
132+
133+
} // namespace DCC_NAMESPACE
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
2+
//
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
#pragma once
6+
7+
#include <QWaylandClientExtension>
8+
#include <memory>
9+
10+
// Qt Wayland C++ bindings generated from the protocol XML.
11+
#include "qwayland-treeland-keyboard-state-notify-unstable-v1.h"
12+
13+
namespace DCC_NAMESPACE {
14+
15+
/**
16+
* @brief 封装 treeland_keyboard_state_notify_v1 Wayland 协议,监听键盘修饰键状态变化。
17+
*
18+
* 用法:
19+
* @code
20+
* auto *notify = new KeyboardStateNotify(this);
21+
* connect(notify, &KeyboardStateNotify::numLockChanged, this, [](bool on) {
22+
* // 处理 NumLock 状态变化
23+
* });
24+
* @endcode
25+
*
26+
* 自动创建 watcher 并订阅 NumLock 状态变化。
27+
*/
28+
class KeyboardStateNotify
29+
: public QWaylandClientExtensionTemplate<KeyboardStateNotify>
30+
, public QtWayland::treeland_keyboard_state_notify_manager_v1
31+
{
32+
Q_OBJECT
33+
Q_PROPERTY(bool available READ available NOTIFY availableChanged)
34+
35+
public:
36+
explicit KeyboardStateNotify(QObject *parent = nullptr);
37+
~KeyboardStateNotify() override;
38+
39+
bool available() const;
40+
41+
Q_SIGNALS:
42+
void availableChanged(bool available);
43+
void numLockChanged(bool on);
44+
45+
private:
46+
class Watcher;
47+
Watcher *m_watcher = nullptr;
48+
bool m_available = false;
49+
50+
void createWatcher(wl_seat *seat);
51+
};
52+
53+
/**
54+
* @brief 封装 treeland_keyboard_state_watcher_v1,负责具体的修饰键监听。
55+
*/
56+
class KeyboardStateNotify::Watcher
57+
: public QObject
58+
, public QtWayland::treeland_keyboard_state_watcher_v1
59+
{
60+
Q_OBJECT
61+
public:
62+
explicit Watcher(KeyboardStateNotify *parent, struct ::treeland_keyboard_state_watcher_v1 *obj);
63+
~Watcher() override;
64+
65+
Q_SIGNALS:
66+
void numLockChanged(bool on);
67+
68+
protected:
69+
void treeland_keyboard_state_watcher_v1_current_state(uint32_t modifier, uint32_t state) override;
70+
void treeland_keyboard_state_watcher_v1_state_changed(uint32_t modifier, uint32_t state) override;
71+
};
72+
73+
} // namespace DCC_NAMESPACE

0 commit comments

Comments
 (0)