168 lines
4.8 KiB
C++
168 lines
4.8 KiB
C++
// Copyright 2010-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>.
|
|
|
|
#include "G15LCDEngine_helper.h"
|
|
|
|
#include "MumbleApplication.h"
|
|
|
|
static LCDEngine *G15LCDEngineNew() {
|
|
return new G15LCDEngineHelper();
|
|
}
|
|
|
|
static LCDEngineRegistrar registrarLCDEngine(G15LCDEngineNew);
|
|
|
|
G15LCDEngineHelper::G15LCDEngineHelper() : LCDEngine() {
|
|
bRunning = false;
|
|
bUnavailable = true;
|
|
|
|
#if defined(Q_OS_WIN)
|
|
qsHelperExecutable = QString::fromLatin1("\"%1/mumble-g15-helper.exe\"")
|
|
.arg(MumbleApplication::instance()->applicationVersionRootPath());
|
|
#elif defined(Q_OS_MAC)
|
|
qsHelperExecutable = QString::fromLatin1("\"%1/mumble-g15-helper\"")
|
|
.arg(MumbleApplication::instance()->applicationVersionRootPath());
|
|
#endif
|
|
|
|
qpHelper = new QProcess(this);
|
|
qpHelper->setObjectName(QLatin1String("Helper"));
|
|
qpHelper->setWorkingDirectory(qApp->applicationDirPath());
|
|
|
|
/*
|
|
* Call our helper to detect whether any Logitech Gamepanel devices
|
|
* are available on the system.
|
|
*/
|
|
qpHelper->start(qsHelperExecutable, QStringList(QLatin1String("/detect")));
|
|
qpHelper->waitForFinished();
|
|
if (qpHelper->exitCode() != 0) {
|
|
qWarning("G15LCDEngine_lglcd: Logitech LCD Manager not detected.");
|
|
return;
|
|
}
|
|
|
|
qlDevices << new G15LCDDeviceHelper(this);
|
|
bUnavailable = false;
|
|
|
|
QMetaObject::connectSlotsByName(this);
|
|
}
|
|
|
|
G15LCDEngineHelper::~G15LCDEngineHelper() {
|
|
setProcessStatus(false);
|
|
}
|
|
|
|
QList< LCDDevice * > G15LCDEngineHelper::devices() const {
|
|
return qlDevices;
|
|
}
|
|
|
|
void G15LCDEngineHelper::setProcessStatus(bool run) {
|
|
if (bUnavailable)
|
|
return;
|
|
|
|
if (run && !bRunning) {
|
|
bRunning = true;
|
|
qpHelper->start(qsHelperExecutable, QStringList(QLatin1String("/mumble")));
|
|
if (!qpHelper->waitForStarted(2000)) {
|
|
qWarning("G15LCDEngine_lglcd: Unable to launch G15 helper.");
|
|
bRunning = false;
|
|
return;
|
|
}
|
|
} else if (!run && bRunning) {
|
|
bRunning = false;
|
|
qpHelper->kill();
|
|
qpHelper->waitForFinished();
|
|
}
|
|
}
|
|
|
|
void G15LCDEngineHelper::on_Helper_finished(int exitCode, QProcess::ExitStatus status) {
|
|
/* Skip the signal if we killed ourselves. */
|
|
if (!bRunning)
|
|
return;
|
|
|
|
if (status == QProcess::CrashExit) {
|
|
qWarning("G15LCDEngine_lglcd: Helper process crashed. Restarting.");
|
|
qpHelper->start(qsHelperExecutable, QStringList(QLatin1String("/mumble")));
|
|
} else if (status == QProcess::NormalExit && exitCode != 0) {
|
|
qWarning("G15LCDEngine_lglcd: Helper process exited. Exit code was: `%i'. Not attempting recovery.", exitCode);
|
|
bUnavailable = true;
|
|
}
|
|
}
|
|
|
|
bool G15LCDEngineHelper::framebufferReady() const {
|
|
return !bUnavailable && (qpHelper->state() == QProcess::Running);
|
|
}
|
|
|
|
void G15LCDEngineHelper::submitFrame(bool alert, unsigned char *buf, qint64 len) {
|
|
char pri = alert ? 1 : 0;
|
|
if ((qpHelper->write(&pri, 1) != 1) || (qpHelper->write(reinterpret_cast< char * >(buf), len) != len))
|
|
qWarning("G15LCDEngine_lglcd: failed to write");
|
|
}
|
|
|
|
/* -- */
|
|
|
|
G15LCDDeviceHelper::G15LCDDeviceHelper(G15LCDEngineHelper *e) : LCDDevice(), bEnabled(false) {
|
|
engine = e;
|
|
}
|
|
|
|
G15LCDDeviceHelper::~G15LCDDeviceHelper() {
|
|
}
|
|
|
|
bool G15LCDDeviceHelper::enabled() {
|
|
return bEnabled;
|
|
}
|
|
|
|
void G15LCDDeviceHelper::setEnabled(bool b) {
|
|
engine->setProcessStatus(b);
|
|
bEnabled = b;
|
|
}
|
|
|
|
void G15LCDDeviceHelper::blitImage(QImage *img, bool alert) {
|
|
Q_ASSERT(img);
|
|
int len = G15_MAX_FBMEM_BITS;
|
|
uchar *tmp = img->bits();
|
|
uchar buf[G15_MAX_FBMEM];
|
|
|
|
if (!engine->framebufferReady())
|
|
return;
|
|
|
|
if (!bEnabled)
|
|
return;
|
|
|
|
/*
|
|
* The amount of copying/conversion we're doing is hideous.
|
|
*
|
|
* To draw to the LCD display using Logitech's SDK, we need to pass
|
|
* it a byte array (in which each byte represents a single pixel on
|
|
* the LCD.)
|
|
*
|
|
* Unfortunately, there's no way out, really. We *could* perhaps draw
|
|
* directly to a monochrome "bytemap" (via Format_Indexed8, and a mono-
|
|
* chrome colormap), but QPainter simply doesn't want to draw to a
|
|
* QImage of Format_Indexed8.
|
|
*
|
|
* (What's even worse is that the byte array passed to the Logitech SDK
|
|
* isn't even the native format of the LCD. It has to convert it once
|
|
* more, when it receives a frame.)
|
|
*/
|
|
for (int i = 0; i < len; i++) {
|
|
int idx = i * 8;
|
|
buf[idx + 7] = tmp[i] & 0x80 ? 0xff : 0x00;
|
|
buf[idx + 6] = tmp[i] & 0x40 ? 0xff : 0x00;
|
|
buf[idx + 5] = tmp[i] & 0x20 ? 0xff : 0x00;
|
|
buf[idx + 4] = tmp[i] & 0x10 ? 0xff : 0x00;
|
|
buf[idx + 3] = tmp[i] & 0x08 ? 0xff : 0x00;
|
|
buf[idx + 2] = tmp[i] & 0x04 ? 0xff : 0x00;
|
|
buf[idx + 1] = tmp[i] & 0x02 ? 0xff : 0x00;
|
|
buf[idx + 0] = tmp[i] & 0x01 ? 0xff : 0x00;
|
|
}
|
|
|
|
engine->submitFrame(alert, buf, G15_MAX_FBMEM);
|
|
}
|
|
|
|
QString G15LCDDeviceHelper::name() const {
|
|
return QString::fromLatin1("Logitech Gamepanel");
|
|
}
|
|
|
|
QSize G15LCDDeviceHelper::size() const {
|
|
return QSize(G15_MAX_WIDTH, G15_MAX_HEIGHT);
|
|
}
|