mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-10-26 11:19:16 +00:00
FIX(client): Migrate Windows shortcuts from versions older than 1.4.0 properly
After 3dc7b00d09, 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.
This commit is contained in:
parent
a4f41775e8
commit
0e17c5394c
@ -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()
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
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));
|
||||
}
|
||||
|
||||
} else if (Global::get().s.uiUpdateCounter == 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
|
||||
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")));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user