Rabbit Remote Control 0.1.0-bate10
Loading...
Searching...
No Matches
DesktopShortcuts.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QRegularExpression>
4#include <QLoggingCategory>
5#include <QStandardPaths>
6#include <QTemporaryDir>
7#include "DesktopShortcuts.h"
8
9static Q_LOGGING_CATEGORY(log, "Plugin.Hook.Desktop.Shortcut")
10
12 : QObject(parent)
13{
14 qDebug(log) << Q_FUNC_INFO;
15 m_desktopEnv = detectDesktopEnvironment();
16 qDebug(log) << "Desktop environment:" << m_desktopEnv;
17
18 // 设置备份路径
19 QString tempDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
20 m_gnomeBackupPath = tempDir + "/gnome_shortcuts_backup.conf";
21 m_kdeBackupPath = tempDir + "/kde_shortcuts_backup.conf";
22}
23
24CDesktopShortcutManager::~CDesktopShortcutManager()
25{
26 qDebug(log) << Q_FUNC_INFO;
27 // 确保退出时恢复快捷键
28 if (m_shortcutsDisabled) {
29 qWarning(log) << "Shortcuts is disabled, restoring ......";
30 restoreAllShortcuts();
31 }
32}
33
34QString CDesktopShortcutManager::detectDesktopEnvironment()
35{
36 QString xdgDesktop = qEnvironmentVariable("XDG_CURRENT_DESKTOP", "").toLower();
37 QString desktopSession = qEnvironmentVariable("DESKTOP_SESSION", "").toLower();
38 QString gdmSession = qEnvironmentVariable("GDMSESSION", "").toLower();
39
40 if (xdgDesktop.contains("gnome") || desktopSession.contains("gnome") || gdmSession.contains("gnome")) {
41 return "GNOME";
42 } else if (xdgDesktop.contains("kde") || desktopSession.contains("plasma") || gdmSession.contains("plasma")) {
43 return "KDE";
44 } else if (xdgDesktop.contains("xfce") || desktopSession.contains("xfce")) {
45 return "XFCE";
46 } else if (xdgDesktop.contains("mate") || desktopSession.contains("mate")) {
47 return "MATE";
48 } else if (xdgDesktop.contains("cinnamon") || desktopSession.contains("cinnamon")) {
49 return "Cinnamon";
50 } else if (xdgDesktop.contains("pantheon") || desktopSession.contains("pantheon")) {
51 return "Pantheon";
52 } else {
53 return "Unknown";
54 }
55}
56
57bool CDesktopShortcutManager::disableAllShortcuts()
58{
59 if (m_shortcutsDisabled) {
60 qDebug(log) << "Shortcuts is disabled";
61 return true;
62 }
63
64 m_shortcutsDisabled = true;
65 bool success = false;
66
67#if defined(Q_OS_LINUX)
68 if("GNOME" == m_desktopEnv || "Cinnamon" == m_desktopEnv || "MATE" == m_desktopEnv) {
69 success = disableGNOMEShortcuts();
70 } else if (m_desktopEnv == "KDE") {
71 success = disableKDEShortcuts();
72 } else if (m_desktopEnv == "XFCE") {
73 success = disableXFCEShortcuts();
74 } else {
75 qWarning(log) << "Unsupported desktop environment:" << m_desktopEnv;
76 return false;
77 }
78#endif
79
80 if (success) {
81 qInfo(log) << "All desktop shortcuts have been disabled";
82 }
83
84 return success;
85}
86
87bool CDesktopShortcutManager::restoreAllShortcuts()
88{
89 if (!m_shortcutsDisabled) {
90 qDebug(log) << "The shortcut key is not disabled, no need to restore.";
91 return true;
92 }
93
94 m_shortcutsDisabled = false;
95 bool success = false;
96
97#if defined(Q_OS_LINUX)
98 if (m_desktopEnv == "GNOME") {
99 success = restoreGNOMEShortcuts();
100 //resetGNOMEShortcuts();
101 } else if (m_desktopEnv == "KDE") {
102 success = restoreKDEShortcuts();
103 } else if (m_desktopEnv == "XFCE") {
104 success = restoreXFCEShortcuts();
105 } else {
106 qWarning(log) << "Unsupported desktop environment:" << m_desktopEnv;
107 return false;
108 }
109#endif
110
111 if (success) {
112 qInfo(log) << "All desktop shortcuts have been restored";
113 }
114
115 return success;
116}
117
118#if defined(Q_OS_LINUX)
119
125bool CDesktopShortcutManager::disableGNOMEShortcuts()
126{
127 qDebug(log) << "Disable GNOME shortcuts ......";
128
129 // 备份当前设置
130 backupGNOMESettings();
131
132 // 禁止设置
133 bool bAllSuccess = true;
134 int nSuccessCount = 0;
135 int nTotalCount = 0;
136 for (auto it = m_gnomeSettings.begin(); it != m_gnomeSettings.end(); ++it) {
137 QString szSchema = it.key();
138 auto keys = it.value();
139 for(auto itKey = keys.begin(); itKey != keys.end(); itKey++) {
140 nTotalCount++;
141 QString szKey = itKey.key();
142 // Super 键
143 if("org.gnome.mutter" == szSchema && "overlay-key" == szKey) {
144 if (runCommand("gsettings", {"set", szSchema, szKey, "''"})) {
145 nSuccessCount++;
146 //qDebug(log) << "Disabled:" << szSchema + ": " + szKey + " = " + "''";
147 } else {
148 qCritical(log) << "Disabled failed:" << szSchema + ": " + szKey + " = " + "''";
149 bAllSuccess = false;
150 }
151 continue;
152 }
153
154 QString szValue = itKey.value();
155 // 是否包含 "[]"
156 // 方法一:直接判断包含 []
157 //if(!(szValue.contains('[') && szValue.contains(']'))) continue;
158 // 方法二:使用正则表达式: \[.*\]
159 if(!szValue.contains(QRegularExpression("\\[.*\\]"))) continue;
160
161 // 去掉 [] 中的内容:
162 /*
163 * 方法一:正则表达式写法:
164 *
165 * (?<=\[)[^\]]*(?=\])
166 *
167 * 说明:
168 * - (?<=\[) — 正向肯定后顾,匹配在 [ 之后的位置
169 * - [^\]]* — 匹配任意不是 ] 的字符(0个或多个)
170 * - (?=\]) — 正向肯定前瞻,匹配在 ] 之前的位置
171 *
172 * 这样匹配到的就是括号内的内容,不包括括号本身。
173 * 注意:QRegularExpression 对前瞻/后顾的支持
174 * Qt 的 QRegularExpression(基于 PCRE)支持前瞻 (?=) 和后顾 (?<=),所以上面的写法是有效的。
175 */
176 //szValue = szValue.replace(QRegularExpression("(?<=\\[)[^\\]]*(?=\\])"), "");
177 /* 方法二:使用捕获组
178 * 正则表达式:
179 * \[([^\]]*)\]
180 * 说明:
181 * |正则 |C++ 字符串|含义 |
182 * |-------|---------|-------------------|
183 * |\[ |"\\[" |匹配左方括号 [ |
184 * |( |"(" |开始捕获组 |
185 * |[^\]] |"[^\\]]" |匹配任意不是 ] 的字符 |
186 * |* |"*" |重复 0 次或多次 |
187 * |) |")" |结束捕获组 |
188 * |\] |"\\]" |匹配右方括号 ] |
189 *
190 * 注意: [^\\]] 在正则中表示字符类 [^]](匹配非 ] 的字符),但在 C++ 字符串中需要对 \ 和 ] 进行转义。
191 */
192 szValue.replace(QRegularExpression("\\[([^\\]]*)\\]"), "[]");
193 if (runCommand("gsettings", {"set", szSchema, szKey, szValue})) {
194 nSuccessCount++;
195 //qDebug(log) << "Disabled:" << szSchema + ": " + szKey + " = " + szValue;
196 } else {
197 qCritical(log) << "Disabled failed:" << szSchema + ": " + szKey + " = " + szValue;
198 bAllSuccess = false;
199 }
200 }
201 }
202
203 qDebug(log) << QString("GNOME is disabled: %1/%2 Success").arg(nSuccessCount).arg(nTotalCount);
204
205 return bAllSuccess;
206}
207
212bool CDesktopShortcutManager::restoreGNOMEShortcuts()
213{
214 qDebug(log) << "Restore GNOME shortcuts ......";
215
216 if (m_gnomeSettings.isEmpty()) {
217 qWarning(log) << "No backup settings are available to restore";
218 return false;
219 }
220
221 bool bAllSuccess = true;
222 int nSuccessCount = 0;
223 int nTotalCount = 0;
224
225 // 恢复备份的设置
226 for (auto it = m_gnomeSettings.begin(); it != m_gnomeSettings.end(); ++it) {
227 QString szSchema = it.key();
228 auto keys = it.value();
229 for(auto itKey = keys.begin(); itKey != keys.end(); itKey++) {
230 nTotalCount++;
231 QString szKey = itKey.key();
232 QString szValue = itKey.value();
233 if (runCommand("gsettings", {"set", szSchema, szKey, szValue})) {
234 nSuccessCount++;
235 //qDebug(log) << "Restored:" << szSchema + ": " + szKey + " = " + szValue;
236 } else {
237 qCritical(log) << "Restore failed:" << szSchema + ": " + szKey + " = " + szValue;
238 bAllSuccess = false;
239 }
240 }
241 }
242
243 qDebug(log) << QString("GNOME shortcut restoration completed: %1/%2 successful").arg(nSuccessCount).arg(nTotalCount);
244
245 /* 重启 GNOME Shell 使设置生效。锁屏和注销需要重启才能生效
246 if (successCount > 0) {
247 qDebug(log) << "Restart GNOME Shell...";
248 if (runCommand("killall", {"-3", "gnome-shell"})) {
249 qDebug(log) << "The GNOME Shell restart signal has been sent";
250 } else {
251 qWarning(log) << "Failed to restart GNOME Shell; some settings may require logging in again to take effect.";
252 }
253 } //*/
254
255 return bAllSuccess;
256}
257
262bool CDesktopShortcutManager::resetGNOMEShortcuts()
263{
264 qDebug(log) << "Reset GNOME shortcuts ......";
265
266 if (m_gnomeSettings.isEmpty()) {
267 qWarning(log) << "No backup settings are available to reset";
268 return false;
269 }
270
271 bool bAllSuccess = true;
272 int nSuccessCount = 0;
273 int nTotalCount = 0;
274
275 // 重置
276 for (auto it = m_gnomeSettings.begin(); it != m_gnomeSettings.end(); ++it) {
277 QString szSchema = it.key();
278 auto keys = it.value();
279 for(auto itKey = keys.begin(); itKey != keys.end(); itKey++) {
280 nTotalCount++;
281 QString szKey = itKey.key();
282 if (runCommand("gsettings", {"reset", szSchema, szKey})) {
283 nSuccessCount++;
284 //qDebug(log) << "Reset:" << szSchema + ": " + szKey;
285 } else {
286 qCritical(log) << "Reset failed:" << szSchema + ": " + szKey;
287 bAllSuccess = false;
288 }
289 }
290 }
291
292 qDebug(log) << QString("GNOME shortcut reset completed: %1/%2 successful").arg(nSuccessCount).arg(nTotalCount);
293
294 /* 重启 GNOME Shell 使设置生效。锁屏和注销需要重启才能生效
295 if (successCount > 0) {
296 qDebug(log) << "Restart GNOME Shell...";
297 if (runCommand("killall", {"-3", "gnome-shell"})) {
298 qDebug(log) << "The GNOME Shell restart signal has been sent";
299 } else {
300 qWarning(log) << "Failed to restart GNOME Shell; some settings may require logging in again to take effect.";
301 }
302 } //*/
303
304 return bAllSuccess;
305}
306
311int CDesktopShortcutManager::backupGNOMESettings()
312{
313 int nTotalCount = 0;
314
315 qDebug(log) << "Backup GNOME settings ......";
316
317 m_gnomeSettings.clear();
318
319 struct GNOMESetting {
320 QString schema;
321 QString key;
322 };
323 QVector<GNOMESetting> vKeys = {
324 // Super 键
325 {"org.gnome.mutter", "overlay-key"}
326 };
327 foreach (auto setting, vKeys) {
328 QMap<QString, QString> mKey;
329 QString value = getCommandOutput("gsettings", {"get", setting.schema, setting.key}).trimmed();
330 if (!value.isEmpty()) {
331 nTotalCount++;
332 mKey.insert(setting.key, value);
333 //qDebug(log) << "Backup:" << setting.schema + ": " + setting.key << "=" << value;
334 } else {
335 qWarning(log) << "Backup fail:" << setting.schema + ": " + setting.key;
336 }
337 if(!mKey.isEmpty())
338 m_gnomeSettings.insert(setting.schema, mKey);
339 }
340
341 QVector<QString> vSchemas = {
342 // 媒体键
343 "org.gnome.settings-daemon.plugins.media-keys"
344 };
345
346 // 可以使用下面命令得到 schema
347 // `gsettings list-schemas|grep keybindings`
348 QString szSchemas = getCommandOutput("gsettings", {"list-schemas"});
349 //qDebug(log) << "Schemas:\n" << szSchemas;
350 QStringList lstSchemas = szSchemas.split('\n', Qt::SkipEmptyParts);
351 foreach (const QString &schema, lstSchemas) {
352 if(!(schema.contains("keybindings") || schema.contains("media-keys")))
353 continue;
354 vSchemas.append(schema);
355 }
356
357 foreach (const QString &schema, vSchemas) {
358 // 获取 schema 的所有键
359 QString output = getCommandOutput("gsettings", {"list-keys", schema});
360 if (output.isEmpty()) {
361 qWarning(log) << "Unable to retrieve the schema key:" << schema;
362 continue;
363 }
364
365 QMap<QString, QString> vKey;
366 QStringList keys = output.split('\n', Qt::SkipEmptyParts);
367 //qDebug(log) << QString("Schema %1 has %2 keys").arg(schema).arg(keys.size());
368 foreach (const QString &key, keys) {
369 QString value = getCommandOutput("gsettings", {"get", schema, key}).trimmed();
370 if (!value.isEmpty()) {
371 nTotalCount++;
372 vKey.insert(key, value);
373 //qDebug(log) << "Backup:" << schema + ": " + key << "=" << value;
374 } else {
375 qWarning(log) << "Backup fail:" << schema + ": " + key;
376 }
377 }
378 if(!vKey.isEmpty())
379 m_gnomeSettings.insert(schema, vKey);
380 }
381
382 qDebug(log) << QString("GNOME settings backup completed, a total of %1 settings were backed up").arg(nTotalCount);
383 return nTotalCount;
384}
385
390bool CDesktopShortcutManager::disableKDEShortcuts()
391{
392 qDebug(log) << "Disable KDE shortcuts ......";
393
394 backupKDESettings();
395
396 // 禁用 KDE 全局快捷键
397 bool success = true;
398
399 // 禁用 KWin 快捷键
400 QStringList kwinKeys = {
401 "Window Close", "Window Maximize", "Window Minimize",
402 "Window Fullscreen", "Window to Desktop 1", "Window to Desktop 2",
403 "Switch to Desktop 1", "Switch to Desktop 2", "Expose"
404 };
405
406 for (const QString &key : kwinKeys) {
407 if (!runCommand("kwriteconfig5", {"--file", "kglobalshortcutsrc", "--key", key, "none"})) {
408 success = false;
409 }
410 }
411
412 // 禁用修饰键快捷键
413 if (!runCommand("kwriteconfig5", {"--file", "kwinrc", "--group", "ModifierOnlyShortcuts", "--key", "Meta", ""})) {
414 success = false;
415 }
416
417 /*/ 重启 KWin 使设置生效
418 runCommand("kwin_x11", {"--replace"});//*/
419
420 return success;
421}
422
427bool CDesktopShortcutManager::restoreKDEShortcuts()
428{
429 qDebug(log) << "Restore KDE shortcuts ......";
430
431 // 恢复备份的配置文件
432 QString configDir = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
433
434 if (!m_kdeSettings.isEmpty()) {
435 for (auto it = m_kdeSettings.begin(); it != m_kdeSettings.end(); ++it) {
436 QStringList parts = it.key().split("|");
437 if (parts.size() == 3) {
438 QString file = parts[0];
439 QString group = parts[1];
440 QString key = parts[2];
441
442 if (!runCommand("kwriteconfig5", {"--file", file, "--group", group, "--key", key, it.value()})) {
443 qWarning(log) << "Failed to restore KDE setting:" << file << group << key;
444 }
445 }
446 }
447 }
448
449 /*/ 重启 KWin
450 runCommand("kwin_x11", {"--replace"});//*/
451
452 return true;
453}
454
466int CDesktopShortcutManager::backupKDESettings()
467{
468 int nCount = 0;
469 qDebug(log) << "Backup KDE settings ......";
470
471 QString configDir = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
472
473 // 备份重要的 KDE 配置文件
474 QStringList configFiles = {
475 "kglobalshortcutsrc",
476 "kwinrc",
477 "khotkeysrc"
478 };
479
480 for (const QString &file : configFiles) {
481 QString sourcePath = configDir + "/" + file;
482 if (QFile::exists(sourcePath)) {
483 backupFile(sourcePath, m_kdeBackupPath + "_" + file);
484 }
485 }
486
487 // 也备份关键设置到内存
488 QStringList settings = {
489 "kglobalshortcutsrc|kwin|Window Close",
490 "kglobalshortcutsrc|kwin|Window Maximize",
491 "kglobalshortcutsrc|kwin|Window Minimize",
492 "kwinrc|ModifierOnlyShortcuts|Meta"
493 };
494
495 for (const QString &setting : settings) {
496 QStringList parts = setting.split("|");
497 if (parts.size() == 3) {
498 QString value = getCommandOutput("kreadconfig5", {"--file", parts[0], "--group", parts[1], "--key", parts[2]});
499 m_kdeSettings[setting] = value.trimmed();
500 }
501 }
502
503 return nCount;
504}
505
510bool CDesktopShortcutManager::disableXFCEShortcuts()
511{
512 qDebug(log) << "Disable XFCE settings ......";
513
514 // 先备份当前设置
515 backupXFCEShortcuts();
516
517 if (m_xfceSettings.isEmpty()) {
518 qWarning(log) << "No XFCE settings to disable";
519 return false;
520 }
521
522 bool bAllSuccess = true;
523 int nSuccessCount = 0;
524 int nTotalCount = 0;
525
526 // 遍历所有备份的快捷键,将其设置为空或无效值
527 for (auto it = m_xfceSettings.begin(); it != m_xfceSettings.end(); ++it) {
528 nTotalCount++;
529 QString property = it.key();
530 QString value = it.value();
531
532 /*
533 // 跳过一些系统必需的快捷键(如果不想禁用的话)
534 // 例如:保留窗口管理器的基本功能
535 if (property.contains("/xfwm4/system/") ||
536 property.contains("/xfwm4/default/")) {
537 qDebug(log) << "Skip system shortcut:" << property;
538 continue;
539 }//*/
540
541 // 对于 XFCE,使用 xfconf-query 重置快捷键
542 // 方法1:将值设置为空字符串(对于某些类型的快捷键有效)
543 // 方法2:使用 --reset 重置为默认值
544 // 方法3:设置为无效的值
545
546 QStringList args;
547 args << "--channel" << "xfce4-keyboard-shortcuts";
548
549 // 检查属性类型,有些是 string 类型,有些是 int 类型
550 // 尝试重置该属性
551 args << "--reset" << "--property" << property;
552
553 if (runCommand("xfconf-query", args)) {
554 nSuccessCount++;
555 qDebug(log) << "Disabled:" << property << "=" << value;
556 } else {
557 // 如果重置失败,尝试设置为空值
558 QStringList setArgs;
559 setArgs << "--channel" << "xfce4-keyboard-shortcuts"
560 << "--property" << property
561 << "--set" << "";
562
563 if (runCommand("xfconf-query", setArgs)) {
564 nSuccessCount++;
565 qDebug(log) << "Disabled (set empty):" << property << "=" << value;
566 } else {
567 qCritical(log) << "Disabled failed:" << property;
568 bAllSuccess = false;
569 }
570 }
571 }
572
573 qDebug(log) << QString("XFCE shortcuts disabled: %1/%2 success").arg(nSuccessCount).arg(nTotalCount);
574
575 // 通知 XFCE 设置已更改
576 //runCommand("xfce4-settings-helper", {"--restart"});
577 return bAllSuccess;
578}
579
610int CDesktopShortcutManager::backupXFCEShortcuts()
611{
612 int nCount = 0;
613 qDebug(log) << "Backup XFCE settings ......";
614
615 // 清空之前备份
616 m_xfceSettings.clear();
617
618 // 获取 XFCE 键盘快捷键的所有配置
619 // xfconf-query --channel xfce4-keyboard-shortcuts -lv
620 QString output = getCommandOutput("xfconf-query", {"--channel", "xfce4-keyboard-shortcuts", "-lv"});
621 if (output.isEmpty()) {
622 qWarning(log) << "Unable to get XFCE keyboard shortcuts configuration";
623 return 0;
624 }
625
626 // 解析输出格式: "/property/path value"
627 // 例如: "/xfwm4/custom/<Alt>F4 close_window"
628 // "/commands/custom/<Primary><Alt>T xfce4-terminal"
629 // "/xfwm4/custom/<Super>d show_desktop"
630 // 注意:有些属性可能只有路径而没有值,需要跳过
631 QStringList lines = output.split('\n', Qt::SkipEmptyParts);
632
633 foreach(const QString &line, lines) {
634 // 使用正则表达式解析: 路径 + 值
635 // 格式: "/path/to/property value"
636 QRegularExpression regex("^(\"[^\"]*\"|/[^\\s]+)\\s+(.*)$");
637 QRegularExpressionMatch match = regex.match(line);
638
639 if (match.hasMatch()) {
640 QString property = match.captured(1);
641 // 移除可能的引号
642 if (property.startsWith('"') && property.endsWith('"')) {
643 property = property.mid(1, property.length() - 2);
644 }
645
646 QString value = match.captured(2).trimmed();
647
648 // 存储配置到内存
649 m_xfceSettings[property] = value;
650 nCount++;
651 qDebug(log) << "Backup:" << property << " = " << value;
652 } else {
653 // 可能是一些只有属性没有值的行,或者是其他格式
654 qDebug(log) << "Skipping line (unable to parse):" << line;
655 }
656 }
657
658 /*
659 // 同时备份配置文件本身作为额外保障
660 QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)
661 + "/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml";
662
663 if (QFile::exists(configPath)) {
664 // 构建备份路径
665 QString backupDir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
666 QString backupFile = backupDir + "/xfce4-keyboard-shortcuts_backup.xml";
667
668 if (backupFile(configPath, backupFile)) {
669 qDebug(log) << "Backup configuration file:" << configPath << "->" << backupFile;
670 } else {
671 qWarning(log) << "Failed to backup configuration file:" << configPath;
672 }
673 }//*/
674
675 qDebug(log) << QString("XFCE settings backup completed, a total of %1 settings were backed up").arg(nCount);
676 return nCount;
677}
678
683bool CDesktopShortcutManager::restoreXFCEShortcuts()
684{
685 qDebug(log) << "Restore XFCE settings ......";
686
687 if (m_xfceSettings.isEmpty()) {
688 qWarning(log) << "No backup settings are available to restore";
689 return false;
690 }
691
692 bool bAllSuccess = true;
693 int nSuccessCount = 0;
694 int nTotalCount = 0;
695
696 // 恢复备份的设置
697 for (auto it = m_xfceSettings.begin(); it != m_xfceSettings.end(); ++it) {
698 nTotalCount++;
699 QString property = it.key();
700 QString value = it.value();
701
702 /*
703 // 跳过系统快捷键
704 if (property.contains("/xfwm4/system/") ||
705 property.contains("/xfwm4/default/")) {
706 qDebug(log) << "Skip system shortcut restore:" << property;
707 continue;
708 }//*/
709
710 // 恢复快捷键设置
711 QStringList args;
712 args << "--channel" << "xfce4-keyboard-shortcuts"
713 << "--property" << property
714 << "--set" << value;
715
716 if (runCommand("xfconf-query", args)) {
717 nSuccessCount++;
718 qDebug(log) << "Restored:" << property << "=" << value;
719 } else {
720 qCritical(log) << "Restore failed:" << property << "=" << value;
721 bAllSuccess = false;
722 }
723 }
724
725 qDebug(log) << QString("XFCE shortcuts restored: %1/%2 success").arg(nSuccessCount).arg(nTotalCount);
726
727 // 通知 XFCE 设置已更改
728 //runCommand("xfce4-settings-helper", {"--restart"});
729 return bAllSuccess;
730}
731
732#endif // #if defined(Q_OS_LINUX)
733
734// 通用工具方法
735bool CDesktopShortcutManager::runCommand(const QString &program, const QStringList &args, int timeout)
736{
737 QProcess process;
738 process.setProgram(program);
739 if(!args.isEmpty())
740 process.setArguments(args);
741
742 //qDebug(log) << "Command:" << program << args;
743
744 process.start();
745
746 if (!process.waitForFinished(timeout)) {
747 qWarning(log) << "Command timeout:" << program << args;
748 return false;
749 }
750
751 if (process.exitCode() != 0) {
752 QString errorOutput = process.readAllStandardError();
753 qWarning(log) << "Command failed:" << program << args
754 << "exit code:" << process.exitCode()
755 << "failed:" << errorOutput;
756 return false;
757 }
758
759 QString standardOutput = process.readAllStandardOutput();
760 if (!standardOutput.isEmpty()) {
761 qDebug(log) << "Command output:" << standardOutput.trimmed();
762 }
763
764 return true;
765}
766
767QString CDesktopShortcutManager::getCommandOutput(const QString &program, const QStringList &args)
768{
769 QProcess process;
770 process.start(program, args);
771
772 if (process.waitForFinished(5000) && process.exitCode() == 0) {
773 return process.readAllStandardOutput();
774 }
775
776 return "";
777}
778
779bool CDesktopShortcutManager::backupFile(const QString &sourcePath, const QString &backupPath)
780{
781 return QFile::copy(sourcePath, backupPath);
782}
783
784bool CDesktopShortcutManager::restoreFile(const QString &backupPath, const QString &targetPath)
785{
786 if (QFile::exists(targetPath)) {
787 QFile::remove(targetPath);
788 }
789 return QFile::copy(backupPath, targetPath);
790}
Manage desktop shortcut keys.