168 lines
4.8 KiB
C++
168 lines
4.8 KiB
C++
// Copyright 2009-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_lglcd.h"
|
|
|
|
#define G15_MAX_DEV 5
|
|
#define G15_MAX_WIDTH 160
|
|
#define G15_MAX_HEIGHT 43
|
|
#define G15_MAX_BPP 1
|
|
#define G15_MAX_FBMEM (G15_MAX_WIDTH * G15_MAX_HEIGHT * G15_MAX_BPP)
|
|
#define G15_MAX_FBMEM_BITS (G15_MAX_FBMEM / 8)
|
|
#if defined(WIN32)
|
|
# define G15_WIDGET_NAME L"Mumble G15 Display"
|
|
#elif defined(APPLE)
|
|
# define G15_WIDGET_NAME CFSTR("Mumble G15 Display")
|
|
#endif
|
|
|
|
static LCDEngine *G15LCDEngineNew() {
|
|
return new G15LCDEngineLGLCD();
|
|
}
|
|
|
|
static LCDEngineRegistrar registrarG15LCD_lglcd(G15LCDEngineNew);
|
|
|
|
G15LCDEngineLGLCD::G15LCDEngineLGLCD() : LCDEngine() {
|
|
DWORD dwErr;
|
|
|
|
ZeroMemory(&llcceConnect, sizeof(llcceConnect));
|
|
ZeroMemory(&llcContext, sizeof(llcContext));
|
|
|
|
llcceConnect.appFriendlyName = G15_WIDGET_NAME;
|
|
llcceConnect.isAutostartable = FALSE;
|
|
llcceConnect.isPersistent = FALSE;
|
|
llcceConnect.dwAppletCapabilitiesSupported = LGLCD_APPLET_CAP_BASIC | LGLCD_APPLET_CAP_BW;
|
|
llcceConnect.connection = LGLCD_INVALID_CONNECTION;
|
|
|
|
llcContext.device = LGLCD_INVALID_DEVICE;
|
|
|
|
dwErr = lgLcdInit();
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
qWarning() << "LGLCD: Unable to initialize Logitech LCD library" << dwErr;
|
|
return;
|
|
}
|
|
|
|
dwErr = lgLcdConnectEx(&llcceConnect);
|
|
if (dwErr != ERROR_SUCCESS) {
|
|
qWarning() << "LGLCD: Unable to connect to Logitech LCD manager" << dwErr;
|
|
return;
|
|
}
|
|
|
|
|
|
qlDevices << new G15LCDDeviceLGLCD(this);
|
|
|
|
QMetaObject::connectSlotsByName(this);
|
|
}
|
|
|
|
G15LCDEngineLGLCD::~G15LCDEngineLGLCD() {
|
|
if (llcContext.device != LGLCD_INVALID_DEVICE) {
|
|
lgLcdClose(llcContext.device);
|
|
llcContext.device = LGLCD_INVALID_DEVICE;
|
|
}
|
|
if (llcceConnect.connection != LGLCD_INVALID_CONNECTION) {
|
|
lgLcdDisconnect(llcceConnect.connection);
|
|
llcceConnect.connection = LGLCD_INVALID_CONNECTION;
|
|
}
|
|
lgLcdDeInit();
|
|
}
|
|
|
|
QList< LCDDevice * > G15LCDEngineLGLCD::devices() const {
|
|
return qlDevices;
|
|
}
|
|
|
|
/* -- */
|
|
|
|
G15LCDDeviceLGLCD::G15LCDDeviceLGLCD(G15LCDEngineLGLCD *e) : LCDDevice(), bEnabled(false) {
|
|
engine = e;
|
|
}
|
|
|
|
G15LCDDeviceLGLCD::~G15LCDDeviceLGLCD() {
|
|
}
|
|
|
|
bool G15LCDDeviceLGLCD::enabled() {
|
|
return bEnabled;
|
|
}
|
|
|
|
void G15LCDDeviceLGLCD::setEnabled(bool b) {
|
|
bEnabled = b;
|
|
|
|
if (bEnabled && (engine->llcContext.device == LGLCD_INVALID_DEVICE)) {
|
|
ZeroMemory(&engine->llcContext, sizeof(engine->llcContext));
|
|
engine->llcContext.connection = engine->llcceConnect.connection;
|
|
engine->llcContext.device = LGLCD_INVALID_DEVICE;
|
|
engine->llcContext.deviceType = LGLCD_DEVICE_BW;
|
|
|
|
DWORD dwErr = lgLcdOpenByType(&engine->llcContext);
|
|
|
|
} else if (!bEnabled && (engine->llcContext.device != LGLCD_INVALID_DEVICE)) {
|
|
lgLcdClose(engine->llcContext.device);
|
|
engine->llcContext.device = LGLCD_INVALID_DEVICE;
|
|
}
|
|
}
|
|
|
|
void G15LCDDeviceLGLCD::blitImage(QImage *img, bool alert) {
|
|
Q_ASSERT(img);
|
|
int len = G15_MAX_FBMEM_BITS;
|
|
uchar *tmp = img->bits();
|
|
|
|
lgLcdBitmap160x43x1 bitmap;
|
|
unsigned char *buf = bitmap.pixels;
|
|
|
|
if (engine->llcContext.device == LGLCD_INVALID_DEVICE)
|
|
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;
|
|
}
|
|
|
|
bitmap.hdr.Format = LGLCD_BMP_FORMAT_160x43x1;
|
|
|
|
DWORD dwErr =
|
|
lgLcdUpdateBitmap(engine->llcContext.device, &bitmap.hdr,
|
|
alert ? LGLCD_SYNC_UPDATE(LGLCD_PRIORITY_ALERT) : LGLCD_SYNC_UPDATE(LGLCD_PRIORITY_NORMAL));
|
|
}
|
|
|
|
QString G15LCDDeviceLGLCD::name() const {
|
|
return QString::fromLatin1("Logitech Gamepanel");
|
|
}
|
|
|
|
QSize G15LCDDeviceLGLCD::size() const {
|
|
return QSize(G15_MAX_WIDTH, G15_MAX_HEIGHT);
|
|
}
|
|
|
|
#undef G15_MAX_DEV
|
|
#undef G15_MAX_WIDTH
|
|
#undef G15_MAX_HEIGHT
|
|
#undef G15_MAX_BPP
|
|
#undef G15_MAX_FBMEM
|
|
#undef G15_MAX_FBMEM_BITS
|
|
#undef G15_WIDGET_NAME
|