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 <codecvt>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QUuid>
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// clang-format off
|
// 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()
|
GlobalShortcutWin::GlobalShortcutWin()
|
||||||
#ifdef USE_XBOXINPUT
|
#ifdef USE_XBOXINPUT
|
||||||
: m_xinputDevices(0), m_xinputLastPacket()
|
: m_xinputDevices(0), m_xinputLastPacket()
|
||||||
|
|||||||
@ -26,6 +26,10 @@ class GlobalShortcutWin : public GlobalShortcutEngine {
|
|||||||
public:
|
public:
|
||||||
static void registerMetaTypes();
|
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
|
/// Inject a native Windows raw input message into GlobalShortcutWin's
|
||||||
/// thread. This method is meant to be called from the main thread
|
/// thread. This method is meant to be called from the main thread
|
||||||
/// to pass native Windows keyboard messages to GlobalShortcutWin.
|
/// to pass native Windows keyboard messages to GlobalShortcutWin.
|
||||||
|
|||||||
@ -12,6 +12,9 @@
|
|||||||
#include "Cert.h"
|
#include "Cert.h"
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "DeveloperConsole.h"
|
#include "DeveloperConsole.h"
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
# include "GlobalShortcut_win.h"
|
||||||
|
#endif
|
||||||
#include "LCD.h"
|
#include "LCD.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "LogEmitter.h"
|
#include "LogEmitter.h"
|
||||||
@ -706,19 +709,35 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
// Configuration updates
|
// Configuration updates
|
||||||
bool runaudiowizard = false;
|
bool runaudiowizard = false;
|
||||||
if (Global::get().s.uiUpdateCounter == 0) {
|
switch (Global::get().s.uiUpdateCounter) {
|
||||||
// Previous version was an pre 1.2.3 release or this is the first run
|
case 0:
|
||||||
runaudiowizard = true;
|
// 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) {
|
shortcuts = migratedShortcuts;
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (runaudiowizard) {
|
if (runaudiowizard) {
|
||||||
@ -727,7 +746,7 @@ int main(int argc, char **argv) {
|
|||||||
delete aw;
|
delete aw;
|
||||||
}
|
}
|
||||||
|
|
||||||
Global::get().s.uiUpdateCounter = 2;
|
Global::get().s.uiUpdateCounter = 3;
|
||||||
|
|
||||||
if (!CertWizard::validateCert(Global::get().s.kpCertificate)) {
|
if (!CertWizard::validateCert(Global::get().s.kpCertificate)) {
|
||||||
QFile qf(qdCert.absoluteFilePath(QLatin1String("MumbleAutomaticCertificateBackup.p12")));
|
QFile qf(qdCert.absoluteFilePath(QLatin1String("MumbleAutomaticCertificateBackup.p12")));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user