155 lines
6.1 KiB
C++
155 lines
6.1 KiB
C++
// Copyright 2015-2023 The Mumble Developers. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the LICENSE file at the root of the
|
|
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
|
|
|
|
/* SPECIFICATION
|
|
* The code interfacing with the Logitech G-Keys DLL was implemented using the
|
|
* following spec:
|
|
*
|
|
* The G-keys DLL lives in
|
|
* "C:\Program Files\Logitech Gaming Software\SDK\G-key\x64\LogitechGkey.dll" for x64 and
|
|
* "C:\Program Files\Logitech Gaming Software\SDK\G-key\x86\LogitechGkey.dll" for x86.
|
|
*
|
|
* Its location can also be read from the registry, using the following keys:
|
|
*
|
|
* x86:
|
|
* "HKEY_CLASSES_ROOT\CLSID\{7bded654-f278-4977-a20f-6e72a0d07859}\ServerBinary"
|
|
*
|
|
* x64:
|
|
* "HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{7bded654-f278-4977-a20f-6e72a0d07859}\ServerBinary"
|
|
*
|
|
* The registry keys are needed if a user installed the Logitech Gaming
|
|
* Software in a non-standard location.
|
|
*
|
|
* The DLL has an init function, it's called "LogiGkeyInit". It takes a
|
|
* pointer, but the parameter must always be nullptr. The function returns a BOOL
|
|
* as a status code.
|
|
*
|
|
* The DLL also has a shutdown function, called "LogiGkeyShutdown". It takes
|
|
* no parameters and does not return anything.
|
|
*
|
|
* You can poll for button states with the DLL using the functions
|
|
* "LogiGkeyIsMouseButtonPressed" and "LogiGkeyIsKeyboardGkeyPressed".
|
|
*
|
|
* The function "LogiGkeyIsMouseButtonPressed" takes a single int parameter, a
|
|
* button number. Mouse button numbers run from 6 up to and including 20. The
|
|
* function returns a BOOL that is true if the button is pressed, and false if
|
|
* not.
|
|
*
|
|
* The function "LogiGkeyIsKeyboardGkeyPressed" takes two int parameters, a
|
|
* button number and a mode number. Keyboard button numbers run from 1 up to
|
|
* and including 29. The mode number can 1, 2 or 3. The mode checks the button
|
|
* state in a specific mode. Typically, one queries all buttons for all modes,
|
|
* so one ends up with 29*3 calls to the function. The function returns a BOOL
|
|
* that is true if the button in the given mode is pressed, and false if not.
|
|
*
|
|
* There are also two functions, "LogiGkeyGetMouseButtonString" and
|
|
* "LogiGkeyGetKeyboardGkeyString". They take the same parameters as the
|
|
* polling functions above, but do not check whether the button is pressed or
|
|
* not. Instead, they return the name of the button being queried as a pointer
|
|
* to a NUL-terminated array of wchar_t's. Presumably, the pointer will be
|
|
* nullptr if the name cannot be retrieved or translated.
|
|
*/
|
|
|
|
/* USAGE
|
|
* In order to use the gkeys on a logitech keyboard, any user must have the
|
|
* Logitech Gaming Software version 8.55+ installed on their computer. Then
|
|
* (re)start mumble. When mumble initializes the library, the LGS (Logitech
|
|
* Gaming Software) will create a profile called "mumble", featuring the mumble
|
|
* icon. In LGS, right click this icon, and select either "Set as Default" or
|
|
* "Set as Persistent". (See "What are persistent and default profiles?" in the
|
|
* LGS help by clicking on the "?" icon on the LGS window, or at
|
|
* http://www.logitech.com/assets/51813/3/lgs-guide.pdf). If mumble is not set
|
|
* as the default or persistent profile, then your keys will not be active
|
|
* unless mumble is the active window.
|
|
*/
|
|
|
|
#include "GKey.h"
|
|
|
|
#ifdef Q_CC_GNU
|
|
# define RESOLVE(var) \
|
|
{ \
|
|
var = reinterpret_cast< __typeof__(var) >(qlLogiGkey.resolve(#var)); \
|
|
bValid = bValid && var; \
|
|
}
|
|
#else
|
|
# define RESOLVE(var) \
|
|
{ \
|
|
*reinterpret_cast< void ** >(&var) = static_cast< void * >(qlLogiGkey.resolve(#var)); \
|
|
bValid = bValid && var; \
|
|
}
|
|
#endif
|
|
|
|
const QUuid GKeyLibrary::quMouse = QUuid(QString::fromLatin1(GKEY_MOUSE_GUID));
|
|
const QUuid GKeyLibrary::quKeyboard = QUuid(QString::fromLatin1(GKEY_KEYBOARD_GUID));
|
|
|
|
GKeyLibrary::GKeyLibrary() {
|
|
QStringList alternatives;
|
|
|
|
HKEY key = nullptr;
|
|
DWORD type = 0;
|
|
WCHAR wcLocation[510];
|
|
DWORD len = 510;
|
|
if (RegOpenKeyEx(GKEY_LOGITECH_DLL_REG_HKEY, GKEY_LOGITECH_DLL_REG_PATH, 0, KEY_READ, &key) == ERROR_SUCCESS) {
|
|
LONG err = RegQueryValueEx(key, L"", nullptr, &type, reinterpret_cast< LPBYTE >(wcLocation), &len);
|
|
if (err == ERROR_SUCCESS && type == REG_SZ) {
|
|
QString qsLocation = QString::fromUtf16(reinterpret_cast< ushort * >(wcLocation), len / 2);
|
|
qWarning("GKeyLibrary: Found ServerBinary with libLocation = \"%s\", len = %lu", qPrintable(qsLocation),
|
|
static_cast< unsigned long >(len));
|
|
alternatives << qsLocation;
|
|
} else {
|
|
qWarning("GKeyLibrary: Error looking up ServerBinary (Error: 0x%lx, Type: 0x%lx, len: %lu)",
|
|
static_cast< unsigned long >(err), static_cast< unsigned long >(type),
|
|
static_cast< unsigned long >(len));
|
|
}
|
|
}
|
|
|
|
alternatives << QString::fromLatin1(GKEY_LOGITECH_DLL_DEFAULT_LOCATION);
|
|
foreach (const QString &lib, alternatives) {
|
|
qlLogiGkey.setFileName(lib);
|
|
|
|
if (qlLogiGkey.load()) {
|
|
bValid = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
RESOLVE(LogiGkeyInit);
|
|
RESOLVE(LogiGkeyShutdown);
|
|
RESOLVE(LogiGkeyIsMouseButtonPressed);
|
|
RESOLVE(LogiGkeyIsKeyboardGkeyPressed);
|
|
RESOLVE(LogiGkeyGetMouseButtonString);
|
|
RESOLVE(LogiGkeyGetKeyboardGkeyString);
|
|
|
|
if (bValid)
|
|
bValid = LogiGkeyInit(nullptr);
|
|
}
|
|
|
|
GKeyLibrary::~GKeyLibrary() {
|
|
if (LogiGkeyShutdown)
|
|
LogiGkeyShutdown();
|
|
}
|
|
|
|
bool GKeyLibrary::isValid() const {
|
|
return bValid;
|
|
}
|
|
|
|
bool GKeyLibrary::isMouseButtonPressed(int button) {
|
|
return LogiGkeyIsMouseButtonPressed(button);
|
|
}
|
|
|
|
bool GKeyLibrary::isKeyboardGkeyPressed(int key, int mode) {
|
|
return LogiGkeyIsKeyboardGkeyPressed(key, mode);
|
|
}
|
|
|
|
QString GKeyLibrary::getMouseButtonString(int button) {
|
|
return QString::fromWCharArray(LogiGkeyGetMouseButtonString(button));
|
|
}
|
|
|
|
QString GKeyLibrary::getKeyboardGkeyString(int key, int mode) {
|
|
return QString::fromWCharArray(LogiGkeyGetKeyboardGkeyString(key, mode));
|
|
}
|
|
|
|
#undef RESOLVE
|