Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavide Beatrici <git@davidebeatrici.dev>2021-07-25 01:34:27 +0300
committerRobert Adam <dev@robert-adam.de>2021-07-26 09:01:34 +0300
commit44c4f41d3e5f3c8f83378781f3b5fc16a7883a65 (patch)
tree07b197502e19ce2296e1a283202b5a12de60ab92
parentc54796060773a5b1fb17ba73ffb5c11b2697ef86 (diff)
FIX(client): Migrate Windows shortcuts from versions older than 1.4.0 properly
After 3dc7b00d0919cf2400071deba54ff7f64ee3d9ea, shortcuts saved in the old format would just show up as "Unknown" and not work. This commit implements a proper migration mechanism, making the shortcuts work without any manual steps. Mice, keyboards, Xbox (XInput) controllers and Logitech G-keys devices are supported. Unfortunately shortcuts will have to be registered again for DirectInput devices such as controllers. The migration is performed silently, unless not 100% successful. In that case a message box appears informing the user about how many shortcuts could not be migrated. Please note that running a version of Mumble that uses the old format after the migration results in corruption. As a result, shortcuts would have to be registered again. Fixes #5025.
-rw-r--r--src/mumble/GlobalShortcut_win.cpp101
-rw-r--r--src/mumble/GlobalShortcut_win.h4
-rw-r--r--src/mumble/main.cpp43
3 files changed, 134 insertions, 14 deletions
diff --git a/src/mumble/GlobalShortcut_win.cpp b/src/mumble/GlobalShortcut_win.cpp
index 0d3c989e3..b60155848 100644
--- a/src/mumble/GlobalShortcut_win.cpp
+++ b/src/mumble/GlobalShortcut_win.cpp
@@ -16,10 +16,10 @@
#include <codecvt>
#include <iomanip>
+#include <sstream>
#include <QTimer>
-
-#include <sstream>
+#include <QUuid>
extern "C" {
// clang-format off
@@ -208,6 +208,103 @@ void GlobalShortcutWin::registerMetaTypes() {
}
}
+QList< Shortcut > GlobalShortcutWin::migrateSettings(const QList< Shortcut > &oldShortcuts) {
+ constexpr QUuid keyboardUuid(0x6F1D2B61, 0xD5A0, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
+ constexpr QUuid mouseUuid(0x6F1D2B60, 0xD5A0, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00);
+ constexpr QUuid xinputUuid(0xCA3937E3, 0x640C, 0x4D9E, 0x9E, 0xF3, 0x90, 0x3F, 0x8B, 0x4F, 0xBC, 0xAB);
+ constexpr QUuid gkeyKeyboardUuid(0x153E64E6, 0x98C8, 0x4E, 0x03, 0x80EF, 0x5F, 0xFD, 0x33, 0xD2, 0x5B, 0x8A);
+ constexpr QUuid gkeyMouseUuid(0xC41E60AF, 0x9022, 0x46CF, 0xBC, 0x39, 0x37, 0x98, 0x10, 0x82, 0xD7, 0x16);
+
+ QList< Shortcut > newShortcuts;
+
+ for (Shortcut shortcut : oldShortcuts) {
+ bool ok = true;
+
+ for (QVariant &button : shortcut.qlButtons) {
+ if (!button.isValid()) {
+ // This happens when the user runs a version that uses
+ // the old format after the migration is performed.
+ ok = false;
+ break;
+ }
+
+ if (button.userType() == qMetaTypeId< InputHid >() || button.userType() == qMetaTypeId< InputKeyboard >()
+ || button.userType() == qMetaTypeId< InputMouse >() || button.userType() == qMetaTypeId< InputXinput >()
+ || button.userType() == qMetaTypeId< InputGkey >()) {
+ // Already in the new format.
+ continue;
+ }
+
+ const QVariantList entries = button.toList();
+ if (entries.size() < 2) {
+ ok = false;
+ break;
+ }
+
+ auto value = entries.at(0).toUInt(&ok);
+ if (!ok) {
+ break;
+ }
+
+ const auto uuid = entries.at(1).toUuid();
+ if (uuid == keyboardUuid) {
+ InputKeyboard input;
+ input.code = (value & ~0x8000U) >> 8;
+ input.e0 = value & 0x8000U;
+
+ // With DirectInput the extended bit is:
+ // - Set for the Pause key.
+ // - Unset for the Numlock key.
+ // With raw input it's the opposite.
+ if (input.code == 0x45) {
+ input.e0 = !input.e0;
+ }
+
+ button = QVariant::fromValue(input);
+ } else if (uuid == mouseUuid) {
+ value >>= 8;
+ if (value < 3 || value > 7) {
+ ok = false;
+ break;
+ }
+
+ button = QVariant::fromValue(static_cast< InputMouse >(value - 2));
+#ifdef USE_XBOXINPUT
+ } else if (uuid == xinputUuid) {
+ InputXinput input;
+ input.device = (value >> 24) & 0xFF;
+ input.code = value & 0x00FFFFFF;
+
+ button = QVariant::fromValue(input);
+#endif
+#ifdef USE_GKEY
+ } else if (uuid == gkeyKeyboardUuid) {
+ InputGkey input = {};
+ input.keyboard = true;
+ input.mode = value >> 16;
+ input.button = value & 0xFFFF;
+
+ button = QVariant::fromValue(input);
+ } else if (uuid == gkeyMouseUuid) {
+ InputGkey input = {};
+ input.button = value;
+
+ button = QVariant::fromValue(input);
+#endif
+ } else {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ newShortcuts << shortcut;
+ }
+ }
+
+ return newShortcuts;
+}
+
GlobalShortcutWin::GlobalShortcutWin()
#ifdef USE_XBOXINPUT
: m_xinputDevices(0), m_xinputLastPacket()
diff --git a/src/mumble/GlobalShortcut_win.h b/src/mumble/GlobalShortcut_win.h
index a50d18e45..cd39d7116 100644
--- a/src/mumble/GlobalShortcut_win.h
+++ b/src/mumble/GlobalShortcut_win.h
@@ -26,6 +26,10 @@ class GlobalShortcutWin : public GlobalShortcutEngine {
public:
static void registerMetaTypes();
+ /// @param oldShortcuts List of shortcuts to migrate.
+ /// @returns List of shortcuts in the new format.
+ static QList< Shortcut > migrateSettings(const QList< Shortcut > &oldShortcuts);
+
/// Inject a native Windows raw input message into GlobalShortcutWin's
/// thread. This method is meant to be called from the main thread
/// to pass native Windows keyboard messages to GlobalShortcutWin.
diff --git a/src/mumble/main.cpp b/src/mumble/main.cpp
index 88e8e2455..6c485c4bc 100644
--- a/src/mumble/main.cpp
+++ b/src/mumble/main.cpp
@@ -12,6 +12,9 @@
#include "Cert.h"
#include "Database.h"
#include "DeveloperConsole.h"
+#ifdef Q_OS_WIN
+# include "GlobalShortcut_win.h"
+#endif
#include "LCD.h"
#include "Log.h"
#include "LogEmitter.h"
@@ -706,19 +709,35 @@ int main(int argc, char **argv) {
// Configuration updates
bool runaudiowizard = false;
- if (Global::get().s.uiUpdateCounter == 0) {
- // Previous version was an pre 1.2.3 release or this is the first run
- runaudiowizard = true;
-
- } else if (Global::get().s.uiUpdateCounter == 1) {
- // Previous versions used old idle action style, convert it
+ switch (Global::get().s.uiUpdateCounter) {
+ case 0:
+ // Previous version was an pre 1.2.3 release or this is the first run
+ runaudiowizard = true;
+ // Fallthrough
+ case 1:
+ // Previous versions used old idle action style, convert it
+ if (Global::get().s.iIdleTime == 5 * 60) { // New default
+ Global::get().s.iaeIdleAction = Settings::Nothing;
+ } else {
+ Global::get().s.iIdleTime = 60 * qRound(Global::get().s.iIdleTime / 60.); // Round to minutes
+ Global::get().s.iaeIdleAction = Settings::Deafen; // Old behavior
+ }
+ // Fallthrough
+#ifdef Q_OS_WIN
+ case 2: {
+ QList< Shortcut > &shortcuts = Global::get().s.qlShortcuts;
+ const QList< Shortcut > migratedShortcuts = GlobalShortcutWin::migrateSettings(shortcuts);
+ if (shortcuts.size() > migratedShortcuts.size()) {
+ const uint32_t num = shortcuts.size() - migratedShortcuts.size();
+ QMessageBox::warning(
+ nullptr, QObject::tr("Shortcuts migration incomplete"),
+ QObject::tr("Unfortunately %1 shortcut(s) could not be migrated.\nYou can register them again.")
+ .arg(num));
+ }
- if (Global::get().s.iIdleTime == 5 * 60) { // New default
- Global::get().s.iaeIdleAction = Settings::Nothing;
- } else {
- Global::get().s.iIdleTime = 60 * qRound(Global::get().s.iIdleTime / 60.); // Round to minutes
- Global::get().s.iaeIdleAction = Settings::Deafen; // Old behavior
+ shortcuts = migratedShortcuts;
}
+#endif
}
if (runaudiowizard) {
@@ -727,7 +746,7 @@ int main(int argc, char **argv) {
delete aw;
}
- Global::get().s.uiUpdateCounter = 2;
+ Global::get().s.uiUpdateCounter = 3;
if (!CertWizard::validateCert(Global::get().s.kpCertificate)) {
QFile qf(qdCert.absoluteFilePath(QLatin1String("MumbleAutomaticCertificateBackup.p12")));