From 637e94dfd8ed2ae363ed9c0e05129d06368f91fb Mon Sep 17 00:00:00 2001 From: Phil Taylor Date: Tue, 20 Feb 2024 16:51:42 +0000 Subject: [PATCH] FIx for original Streamdeck (maybe XL as well?) --- usbcontroller.cpp | 219 +++++++++++++++++++++++++++------------------- usbcontroller.h | 13 +-- 2 files changed, 134 insertions(+), 98 deletions(-) diff --git a/usbcontroller.cpp b/usbcontroller.cpp index 10477cf..4878b9b 100644 --- a/usbcontroller.cpp +++ b/usbcontroller.cpp @@ -18,22 +18,23 @@ usbController::usbController() loadKnobs(); // This is a the "master" list of supported devices. Maybe move to settings at some point? - // usbDeviceType, manufacturer, product, usage, usagePage, butons, knobs, leds, maxPayload, iconSize - knownDevices.append(USBTYPE(shuttleXpress,0x0b33,0x0020,0x0000,0x0000,15,2,0,5,0)); - knownDevices.append(USBTYPE(shuttlePro2,0x0b33,0x0030,0x0000,0x0000,15,2,0,5,0)); - knownDevices.append(USBTYPE(shuttlePro2,0x0b33,0x0011,0x0000,0x0000,15,2,0,5,0)); // Actually a ShuttlePro but hopefully will work? - knownDevices.append(USBTYPE(RC28,0x0c26,0x001e,0x0000,0x0000,3,1,3,64,0)); - knownDevices.append(USBTYPE(eCoderPlus, 0x1fc9, 0x0003,0x0000,0x0000,22,4,0,32,0)); // Actually 20 but some bit0 and bit15 aren't used - knownDevices.append(USBTYPE(QuickKeys, 0x28bd, 0x5202,0x0001,0xff0a,10,1,0,32,0)); - knownDevices.append(USBTYPE(StreamDeckMini, 0x0fd9, 0x0063, 0x0000, 0x0000,6,0,0,1024,80)); - knownDevices.append(USBTYPE(StreamDeckMiniV2, 0x0fd9, 0x0090, 0x0000, 0x0000,6,0,0,1024,80)); - knownDevices.append(USBTYPE(StreamDeckOriginal, 0x0fd9, 0x0060, 0x0000, 0x0000,15,0,0,8191,72)); - knownDevices.append(USBTYPE(StreamDeckOriginalV2, 0x0fd9, 0x006d, 0x0000, 0x0000,15,0,0,1024,72)); - knownDevices.append(USBTYPE(StreamDeckOriginalMK2, 0x0fd9, 0x0080, 0x0000, 0x0000,15,0,0,1024,72)); - knownDevices.append(USBTYPE(StreamDeckXL, 0x0fd9, 0x006c, 0x0000, 0x0000,32,0,0,1024,96)); - knownDevices.append(USBTYPE(StreamDeckXLV2, 0x0fd9, 0x008f, 0x0000, 0x0000,32,0,0,1024,96)); - knownDevices.append(USBTYPE(StreamDeckPedal, 0x0fd9, 0x0086, 0x0000, 0x0000,3,0,0,1024,0)); - knownDevices.append(USBTYPE(StreamDeckPlus, 0x0fd9, 0x0084, 0x0000, 0x0000,12,4,0,1024,120)); + // usbDeviceType, manufacturer, product, usage, usagePage, buttons, columns, knobs, leds, maxPayload, iconSize + knownDevices.append(USBTYPE(shuttleXpress,0x0b33,0x0020,0x0000,0x0000,15,0,2,0,5,0)); + knownDevices.append(USBTYPE(shuttlePro2,0x0b33,0x0030,0x0000,0x0000,15,0,2,0,5,0)); + knownDevices.append(USBTYPE(shuttlePro2,0x0b33,0x0011,0x0000,0x0000,15,0,2,0,5,0)); // Actually a ShuttlePro but hopefully will work? + knownDevices.append(USBTYPE(RC28,0x0c26,0x001e,0x0000,0x0000,3,0,1,3,64,0)); + knownDevices.append(USBTYPE(eCoderPlus, 0x1fc9, 0x0003,0x0000,0x0000,22,0,4,0,32,0)); // Actually 20 but some bit0 and bit15 aren't used + knownDevices.append(USBTYPE(QuickKeys, 0x28bd, 0x5202,0x0001,0xff0a,10,0,1,0,32,0)); + knownDevices.append(USBTYPE(StreamDeckMini, 0x0fd9, 0x0063, 0x0000, 0x0000,6,0,0,0,1024,80)); + knownDevices.append(USBTYPE(StreamDeckMiniV2, 0x0fd9, 0x0090, 0x0000, 0x0000,6,0,0,0,1024,80)); + knownDevices.append(USBTYPE(StreamDeckOriginal, 0x0fd9, 0x0060, 0x0000, 0x0000,15,5,0,0,8191,72)); + knownDevices.append(USBTYPE(StreamDeckOriginalV2, 0x0fd9, 0x006d, 0x0000, 0x0000,15,5,0,0,1024,72)); + knownDevices.append(USBTYPE(StreamDeckOriginalMK2, 0x0fd9, 0x0080, 0x0000, 0x0000,15,5,0,0,1024,72)); + knownDevices.append(USBTYPE(StreamDeckXL, 0x0fd9, 0x006c, 0x0000, 0x0000,32,8,0,0,1024,96)); + knownDevices.append(USBTYPE(StreamDeckXLV2, 0x0fd9, 0x008f, 0x0000, 0x0000,32,8,0,0,1024,96)); + knownDevices.append(USBTYPE(StreamDeckPedal, 0x0fd9, 0x0086, 0x0000, 0x0000,3,0,0,0,1024,0)); + knownDevices.append(USBTYPE(StreamDeckPlus, 0x0fd9, 0x0084, 0x0000, 0x0000,12,0,4,0,1024,120)); + knownDevices.append(USBTYPE(XKeysXK3, 0x05f3, 0x04c5, 0x0001, 0x000c,3,0,0,2,32,0)); // So-called "splat" interface? } usbController::~usbController() @@ -606,61 +607,73 @@ void usbController::runTimer() else if (res>=dev->type.buttons && dev->type.model != usbNone) { // Main buttons - if ((quint8)data[1] == 0x00) + if (dev->type.model == usbDeviceType::StreamDeckOriginal) { - for (int i=dev->type.buttons-dev->type.knobs;i>0;i--) { - tempButtons |= ((quint8)data[i+3] & 0x01) << (i-1); + + for (int i = dev->type.buttons-1;i>=0;i--) { + quint8 val = ((i - (i % dev->type.cols)) + (dev->type.cols-1)) - (i % dev->type.cols); + tempButtons |= ((quint8)data[val+1] & 0x01) << (i); } + + qInfo(logUsbControl()) << "RX:" << data.toHex(' '); } - - // Knobs and secondary buttons - if (dev->type.model == StreamDeckPlus) { - if ((quint8)data[1] == 0x03 && (quint8)data[2] == 0x05) + else + { + if ((quint8)data[1] == 0x00) { - // Knob action! - switch ((quint8)data[4]) - { - case 0x00: - // Knob button - for (int i=dev->type.buttons;i>7;i--) - { - tempButtons |= ((quint8)data[i-4] & 0x01) << (i-1); - } - break; - case 0x01: - // Knob moved - for (int i=0;itype.knobs;i++) - { - dev->knobValues[i].value += (qint8)data[i+5]; - } - break; + for (int i = dev->type.buttons - dev->type.knobs;i>0;i--) { + tempButtons |= ((quint8)data[i+3] & 0x01) << (i-1); } } - else if ((quint8)data[1] == 0x02 && (quint8)data[2] == 0x0E) - { - // LCD touch event - int x = ((quint8)data[7] << 8) | ((quint8)data[6] & 0xff); - int y = ((quint8)data[9] << 8) | ((quint8)data[8] & 0xff); - int x2=0; - int y2=0; - QString tt=""; - switch ((quint8)data[4]) - { - case 0x01: - tt="Short"; - break; - case 0x02: - tt="Long"; - break; - case 0x03: - tt="Swipe"; - x2 = ((quint8)data[11] << 8) | ((quint8)data[10] & 0xff); - y2 = ((quint8)data[13] << 8) | ((quint8)data[12] & 0xff); - break; - } - qInfo(logUsbControl()) << QString("%0 touch: %1,%2 to %3,%4").arg(tt).arg(x).arg(y).arg(x2).arg(y2); - } + // Knobs and secondary buttons + if (dev->type.model == StreamDeckPlus) { + if ((quint8)data[1] == 0x03 && (quint8)data[2] == 0x05) + { + // Knob action! + switch ((quint8)data[4]) + { + case 0x00: + // Knob button + for (int i=dev->type.buttons;i>7;i--) + { + tempButtons |= ((quint8)data[i-4] & 0x01) << (i-1); + } + break; + case 0x01: + // Knob moved + for (int i=0;itype.knobs;i++) + { + dev->knobValues[i].value += (qint8)data[i+5]; + } + break; + } + } + else if ((quint8)data[1] == 0x02 && (quint8)data[2] == 0x0E) + { + // LCD touch event + int x = ((quint8)data[7] << 8) | ((quint8)data[6] & 0xff); + int y = ((quint8)data[9] << 8) | ((quint8)data[8] & 0xff); + int x2=0; + int y2=0; + QString tt=""; + switch ((quint8)data[4]) + { + case 0x01: + tt="Short"; + break; + case 0x02: + tt="Long"; + break; + case 0x03: + tt="Swipe"; + x2 = ((quint8)data[11] << 8) | ((quint8)data[10] & 0xff); + y2 = ((quint8)data[13] << 8) | ((quint8)data[12] & 0xff); + break; + } + qInfo(logUsbControl()) << QString("%0 touch: %1,%2 to %3,%4").arg(tt).arg(x).arg(y).arg(x2).arg(y2); + } + } } } @@ -966,7 +979,9 @@ void usbController::sendRequest(USBDEVICE *dev, usbFeatureType feature, int val, case StreamDeckXLV2: case StreamDeckPlus: case StreamDeckPedal: - data.resize(32); + if (!sdv1) + data.resize(32); + switch (feature) { case usbFeatureType::featureFirmware: @@ -1171,7 +1186,8 @@ void usbController::sendRequest(USBDEVICE *dev, usbFeatureType feature, int val, ((dev->type.model == usbDeviceType::StreamDeckPlus && val < 8) || (val < dev->type.buttons))) { - if (val < 8) { + if (val < 8 || dev->type.model != usbDeviceType::StreamDeckPlus) { + QImage butImage(dev->type.iconSize,dev->type.iconSize, QImage::Format_RGB888); if (color != Q_NULLPTR) butImage.fill(*color); @@ -1181,7 +1197,11 @@ void usbController::sendRequest(USBDEVICE *dev, usbFeatureType feature, int val, QPainter butPaint(&butImage); if ( img == Q_NULLPTR) { - butPaint.setFont(QFont("times",16)); + if (dev->type.iconSize == 72) + butPaint.setFont(QFont("times",10)); + else + butPaint.setFont(QFont("times",16)); + butPaint.drawText(butImage.rect(),Qt::AlignCenter | Qt::AlignVCenter, text); } else { butPaint.setCompositionMode(QPainter::CompositionMode_SourceAtop); @@ -1189,12 +1209,27 @@ void usbController::sendRequest(USBDEVICE *dev, usbFeatureType feature, int val, } QBuffer butBuffer(&data2); + QTransform myTransform; + if (dev->type.model == usbDeviceType::StreamDeckOriginal || dev->type.model == usbDeviceType::StreamDeckXL) + { + myTransform.rotate(180); + } + QImage myImage = butImage.transformed(myTransform); if (sdv1) { - butImage.save(&butBuffer, "BMP"); + + myImage.save(&butBuffer, "BMP"); + quint16 payloadLen = dev->type.maxPayload - sizeof(streamdeck_v1_image_header); + + if (dev->type.model == usbDeviceType::StreamDeckOriginal) { + // Special case for buttons on original StreamDeck + val = ((val - (val % dev->type.cols)) + (dev->type.cols-1)) - (val % dev->type.cols) + 1; + payloadLen = data2.size()/2; + } + quint32 rem = data2.size(); - quint16 index = 0; + quint16 index = 1; streamdeck_v1_image_header h1; memset(h1.packet, 0x0, sizeof(h1)); // We can't be sure it is initialized with 0x00! h1.cmd = 0x02; @@ -1202,24 +1237,24 @@ void usbController::sendRequest(USBDEVICE *dev, usbFeatureType feature, int val, h1.button = val; while (rem > 0) { - quint16 length = qMin(quint16(rem),quint16(dev->type.maxPayload-sizeof(h1))); + quint32 length = qMin(quint16(rem),quint16(payloadLen)); data.clear(); - h1.isLast = (quint8)(rem <= dev->type.maxPayload-sizeof(h1) ? 1 : 0); // isLast ? 1 : 0,3 + data.squeeze(); + h1.isLast = (quint8)(rem <= payloadLen ? 1 : 0); // isLast ? 1 : 0,3 h1.index = index; - data.append(QByteArray::fromRawData((const char*)h1.packet,sizeof(h1))); - rem -= length; - data.append(data2.mid(0,length)); + data.append(QByteArray::fromRawData((const char*)h1.packet,0x16)); data.resize(dev->type.maxPayload); - memset(data.data()+length+sizeof(h1),0x0,data.size()-(length+sizeof(h1))); + rem -= length; + data=data.replace(0x10,length,data2.mid(0,length)); res=hid_write(dev->handle, (const unsigned char*)data.constData(), data.size()); - //qInfo(logUsbControl()) << "Sending" << (((quint8)data[7] << 8) | ((quint8)data[6] & 0xff)) << "total=" << data.size() << "payload=" << (((quint8)data[5] << 8) | ((quint8)data[4] & 0xff)) << "last" << (quint8)data[3]; + //qInfo(logUsbControl()) << "Sending len=" << dev->type.maxPayload << h1.index << "total=" << data.size() << "payload=" << length << "last" << h1.isLast; data2.remove(0,length); index++; } } else { - butImage.save(&butBuffer, "JPG"); + myImage.save(&butBuffer, "JPG"); quint32 rem = data2.size(); quint16 index = 0; streamdeck_image_header h; @@ -1414,11 +1449,11 @@ void usbController::loadButtons() defaultButtons.append(BUTTON(StreamDeckOriginal, 7, QRect(263, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); defaultButtons.append(BUTTON(StreamDeckOriginal, 8, QRect(364, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); defaultButtons.append(BUTTON(StreamDeckOriginal, 9, QRect(462, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginal, 10, QRect(332, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginal, 11, QRect(462, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginal, 12, QRect(74, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginal, 13, QRect(204, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginal, 14, QRect(332, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginal, 10, QRect(65, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginal, 11, QRect(165, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginal, 12, QRect(263, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginal, 13, QRect(364, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginal, 14, QRect(462, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); // StreamDeckOriginalMK2 defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 0, QRect(65, 91, 75, 75), Qt::white, &commands[0], &commands[0],true)); @@ -1431,11 +1466,11 @@ void usbController::loadButtons() defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 7, QRect(263, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 8, QRect(364, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 9, QRect(462, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 10, QRect(332, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 11, QRect(462, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 12, QRect(74, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 13, QRect(204, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 14, QRect(332, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 10, QRect(65, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 11, QRect(165, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 12, QRect(263, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 13, QRect(364, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalMK2, 14, QRect(462, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); // StreamDeckOriginalV2 defaultButtons.append(BUTTON(StreamDeckOriginalV2, 0, QRect(65, 91, 75, 75), Qt::white, &commands[0], &commands[0],true)); @@ -1448,11 +1483,11 @@ void usbController::loadButtons() defaultButtons.append(BUTTON(StreamDeckOriginalV2, 7, QRect(263, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); defaultButtons.append(BUTTON(StreamDeckOriginalV2, 8, QRect(364, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); defaultButtons.append(BUTTON(StreamDeckOriginalV2, 9, QRect(462, 190, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalV2, 10, QRect(332, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalV2, 11, QRect(462, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalV2, 12, QRect(74, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalV2, 13, QRect(204, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); - defaultButtons.append(BUTTON(StreamDeckOriginalV2, 14, QRect(332, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalV2, 10, QRect(65, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalV2, 11, QRect(165, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalV2, 12, QRect(263, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalV2, 13, QRect(364, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); + defaultButtons.append(BUTTON(StreamDeckOriginalV2, 14, QRect(462, 291, 75, 75), Qt::white, &commands[0], &commands[0],true)); // StreamDeckMini defaultButtons.append(BUTTON(StreamDeckMini, 0, QRect(113, 86, 100, 80), Qt::white, &commands[0], &commands[0],true)); diff --git a/usbcontroller.h b/usbcontroller.h index 44465f0..0a5b8e8 100644 --- a/usbcontroller.h +++ b/usbcontroller.h @@ -70,18 +70,19 @@ using namespace std; struct USBTYPE { USBTYPE() {} - USBTYPE(usbDeviceType model,quint32 manufacturerId, quint32 productId , quint32 usage, quint32 usagePage, int buttons, int knobs, int leds, int maxPayload, int iconSize) : - model(model), manufacturerId(manufacturerId), productId(productId), usage(usage), usagePage(usagePage), buttons(buttons), knobs(knobs), leds(leds), maxPayload(maxPayload), iconSize(iconSize) {} + USBTYPE(usbDeviceType model,quint32 manufacturerId, quint32 productId , quint32 usage, quint32 usagePage, int buttons, int cols, int knobs, int leds, int maxPayload, int iconSize) : + model(model), manufacturerId(manufacturerId), productId(productId), usage(usage), usagePage(usagePage), buttons(buttons), cols(cols), knobs(knobs), leds(leds), maxPayload(maxPayload), iconSize(iconSize) {} usbDeviceType model = usbNone; quint32 manufacturerId=0; quint32 productId=0; quint32 usage=0; quint32 usagePage=0; - int buttons=0; - int knobs=0; - int leds=0; - int maxPayload=0; + int buttons=0; // How many buttons + int cols=0; // How many columns of buttons + int knobs=0; // How many knobs + int leds=0; // how many leds + int maxPayload=0; // Max allowed payload int iconSize=0; };