#include "LOGIC/Lgc_Core_Private.h" #include "MID/Mid_Ble.h" #include #include #include #include namespace { QString Lgc_Core_GetTimeText() { return QDateTime::currentDateTimeUtc() .toTimeZone(QTimeZone("Asia/Shanghai")) .toString(QStringLiteral("HH:mm:ss.zzz")); } void Lgc_Core_AppendLog(Lgc_Core_Struct_State* p_State, const QString& Text) { if (Text.isEmpty()) { return; } if (p_State->TextLog.isEmpty()) { p_State->TextLog = Text; } else { p_State->TextLog.append(QStringLiteral("\n\n")); p_State->TextLog.append(Text); } if (p_State->TextLog.size() > 24000) { p_State->TextLog = p_State->TextLog.right(20000); } } void Lgc_Core_CollectKeyboardUsage( const QByteArray& UsageBitmap, QVector* p_UsageList, QStringList* p_UsageTextList) { p_UsageList->clear(); p_UsageTextList->clear(); for (quint16 Usage = 0; Usage <= MID_CONST_KEYBOARD_USAGE_MAX; ++Usage) { const int ByteIndex = Usage / 8; const quint8 BitMask = static_cast(1U << (Usage % 8)); const quint8 ByteValue = static_cast(UsageBitmap.at(ByteIndex)); if ((ByteValue & BitMask) == 0) { continue; } p_UsageList->append(Usage); p_UsageTextList->append(Mid_GetKeyboardUsageText(Usage)); } } bool Lgc_Core_HandleBleHidPacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet) { switch (Packet.Source) { case Mid_Enum_RawPacketSource_BleHidKeyboard: case Mid_Enum_RawPacketSource_BleHidConsumer: case Mid_Enum_RawPacketSource_BleHidVendor: case Mid_Enum_RawPacketSource_BleHidVendorCommand: break; default: return false; } if (Packet.ByteArray.isEmpty()) { return false; } switch (static_cast(Packet.ByteArray.at(0))) { case Mid_Enum_ReportId_Nkro: Lgc_Core_HandleNkroPacket(p_State, Packet); return true; case Mid_Enum_ReportId_Consumer: Lgc_Core_HandleConsumerPacket(p_State, Packet); return true; case Mid_Enum_ReportId_Vendor: case Mid_Enum_ReportId_VendorCommand: Lgc_Core_HandleVendorPacket(p_State, Packet); return true; default: return false; } } } // namespace void Lgc_Core_UpdateSendTransportByPacket( Lgc_Core_Struct_State* p_State, Mid_Enum_RawPacketSource Source) { switch (Source) { case Mid_Enum_RawPacketSource_UsbNkroRaw: case Mid_Enum_RawPacketSource_UsbConsumerHid: case Mid_Enum_RawPacketSource_UsbVendorHid: p_State->ActiveSendTransport = Lgc_Core_Enum_SendTransport_Usb; break; case Mid_Enum_RawPacketSource_BleGatt: case Mid_Enum_RawPacketSource_BleHidKeyboard: case Mid_Enum_RawPacketSource_BleHidConsumer: case Mid_Enum_RawPacketSource_BleHidVendor: case Mid_Enum_RawPacketSource_BleHidVendorCommand: p_State->ActiveSendTransport = Lgc_Core_Enum_SendTransport_Ble; break; default: break; } } void Lgc_Core_NormalizeSendTransport(Lgc_Core_Struct_State* p_State) { const bool HasUsb = p_State->DriVendorPort.ReadPort.IsOpened; const bool HasBle = p_State->DriBlePort.IsConnected; if ((p_State->ActiveSendTransport == Lgc_Core_Enum_SendTransport_Usb) && HasUsb) { return; } if ((p_State->ActiveSendTransport == Lgc_Core_Enum_SendTransport_Ble) && HasBle) { return; } if (HasBle && !HasUsb) { p_State->ActiveSendTransport = Lgc_Core_Enum_SendTransport_Ble; } else if (HasUsb && !HasBle) { p_State->ActiveSendTransport = Lgc_Core_Enum_SendTransport_Usb; } else if (!HasUsb && !HasBle) { p_State->ActiveSendTransport = Lgc_Core_Enum_SendTransport_None; } } void Lgc_Core_AppendStatusLog(Lgc_Core_Struct_State* p_State, const QString& Text) { if (!Text.isEmpty()) { Lgc_Core_AppendLog( p_State, QStringLiteral("[%1] 状态\n%2").arg(Lgc_Core_GetTimeText(), Text)); } } void Lgc_Core_AppendPacketLog( Lgc_Core_Struct_State* p_State, const QString& ActionText, const QString& PortName, const QByteArray& Packet, const QString& ExplainText) { QString Text = QStringLiteral("[%1] %2\n端口: %3\nHEX: %4") .arg(Lgc_Core_GetTimeText(), ActionText, PortName, Mid_GetHexText(Packet)); if (!ExplainText.isEmpty()) { Text.append(QLatin1Char('\n')); Text.append(ExplainText); } Lgc_Core_AppendLog(p_State, Text); } void Lgc_Core_ClearAllKeyStates(Lgc_Core_Struct_State* p_State) { p_State->IsVisibleKeyStateValid = false; p_State->VisibleUsageList.clear(); p_State->IsPhysicalKeyStateValid = false; p_State->PhysicalUsageList.clear(); p_State->LastPhysicalUsageList.clear(); } void Lgc_Core_CloseAllPorts(Lgc_Core_Struct_State* p_State) { Dri_Ble_Close(&p_State->DriBlePort); Dri_NkroRaw_Close(&p_State->DriNkroPort); Dri_Consumer_Close(&p_State->DriConsumerPort); Dri_Vendor_Close(&p_State->DriVendorPort); } bool Lgc_Core_SyncSystemState(Lgc_Core_Struct_State* p_State) { const bool OldNumLock = p_State->IsSystemNumLockOn; const bool OldConnected = p_State->IsConnected; const QString OldConnection = p_State->TextConnection; const Lgc_Core_Enum_SendTransport OldSendTransport = p_State->ActiveSendTransport; p_State->IsSystemNumLockOn = (GetKeyState(VK_NUMLOCK) & 0x0001) != 0; p_State->IsConnected = p_State->DriVendorPort.ReadPort.IsOpened || p_State->DriBlePort.IsConnected; Lgc_Core_NormalizeSendTransport(p_State); QStringList Lines; if (p_State->DriVendorPort.ReadPort.IsOpened) { Lines.append(QStringLiteral("已连接 USB Vendor 接口。")); } if (!p_State->DriBlePort.TextEndpointSummary.isEmpty()) { Lines.append(p_State->DriBlePort.TextEndpointSummary); } if (Lines.isEmpty()) { Lines.append(QStringLiteral("未连接到目标设备。")); } p_State->TextConnection = Lines.join(QLatin1Char('\n')); return (OldNumLock != p_State->IsSystemNumLockOn) || (OldConnected != p_State->IsConnected) || (OldConnection != p_State->TextConnection) || (OldSendTransport != p_State->ActiveSendTransport); } void Lgc_Core_HandleNkroPacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet) { Lgc_Core_UpdateSendTransportByPacket(p_State, Packet.Source); QString ExplainText = QStringLiteral("NKRO"); if (!Packet.ByteArray.isEmpty() && (static_cast(Packet.ByteArray.at(0)) == Mid_Enum_ReportId_Nkro) && (Packet.ByteArray.size() == MID_CONST_PACKET_SIZE_NKRO)) { const quint8 Modifier = static_cast(Packet.ByteArray.at(1)); const QByteArray UsageBitmap = Packet.ByteArray.mid(2, MID_CONST_USAGE_BITMAP_SIZE); QVector UsageList; QStringList UsageTextList; Lgc_Core_CollectKeyboardUsage(UsageBitmap, &UsageList, &UsageTextList); p_State->IsVisibleKeyStateValid = true; p_State->VisibleUsageList = UsageList; ExplainText = QStringLiteral("NKRO %1 / %2") .arg(Mid_GetModifierText(Modifier), UsageTextList.isEmpty() ? QStringLiteral("无按键") : UsageTextList.join(QStringLiteral(", "))); } Lgc_Core_AppendPacketLog(p_State, QStringLiteral("收到"), Packet.PortName, Packet.ByteArray, ExplainText); } void Lgc_Core_HandleConsumerPacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet) { Lgc_Core_UpdateSendTransportByPacket(p_State, Packet.Source); QString ExplainText = QStringLiteral("Consumer"); if (!Packet.ByteArray.isEmpty() && (static_cast(Packet.ByteArray.at(0)) == Mid_Enum_ReportId_Consumer) && (Packet.ByteArray.size() == MID_CONST_PACKET_SIZE_CONSUMER)) { const quint16 Usage = static_cast(Packet.ByteArray.at(1)) | (static_cast(static_cast(Packet.ByteArray.at(2))) << 8); ExplainText = QStringLiteral("Consumer %1").arg(Mid_GetConsumerUsageText(Usage)); } Lgc_Core_AppendPacketLog(p_State, QStringLiteral("收到"), Packet.PortName, Packet.ByteArray, ExplainText); } void Lgc_Core_HandleVendorPacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet) { Lgc_Core_UpdateSendTransportByPacket(p_State, Packet.Source); QString ExplainText = QStringLiteral("Vendor"); if (Packet.ByteArray.isEmpty()) { Lgc_Core_AppendPacketLog(p_State, QStringLiteral("收到"), Packet.PortName, Packet.ByteArray, ExplainText); return; } const quint8 ReportId = static_cast(Packet.ByteArray.at(0)); if ((ReportId == Mid_Enum_ReportId_Vendor) && (Packet.ByteArray.size() == MID_CONST_PACKET_SIZE_VENDOR)) { const quint8 Modifier = static_cast(Packet.ByteArray.at(1)); const QByteArray UsageBitmap = Packet.ByteArray.mid(2, MID_CONST_USAGE_BITMAP_SIZE); QVector UsageList; QStringList UsageTextList; Lgc_Core_CollectKeyboardUsage(UsageBitmap, &UsageList, &UsageTextList); p_State->IsPhysicalKeyStateValid = true; p_State->PhysicalUsageList = UsageList; ExplainText = QStringLiteral("Vendor %1 / %2") .arg(Mid_GetModifierText(Modifier), UsageTextList.isEmpty() ? QStringLiteral("无按键") : UsageTextList.join(QStringLiteral(", "))); } else if ((ReportId == Mid_Enum_ReportId_VendorCommand) && (Packet.ByteArray.size() >= 2)) { ExplainText = QStringLiteral("VendorCmd 0x%1") .arg(static_cast(Packet.ByteArray.at(1)), 2, 16, QLatin1Char('0')) .toUpper(); } Lgc_Core_AppendPacketLog(p_State, QStringLiteral("收到"), Packet.PortName, Packet.ByteArray, ExplainText); } void Lgc_Core_HandleBlePacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet) { Lgc_Core_UpdateSendTransportByPacket(p_State, Packet.Source); if (Lgc_Core_HandleBleHidPacket(p_State, Packet)) { return; } if (Packet.Source != Mid_Enum_RawPacketSource_BleGatt) { Lgc_Core_AppendPacketLog(p_State, QStringLiteral("收到"), Packet.PortName, Packet.ByteArray, QStringLiteral("BLE")); return; } const QString ExplainText = Packet.ByteArray.isEmpty() ? QStringLiteral("BLE") : QStringLiteral("BLE %1").arg(Mid_GetBleOpcodeText(static_cast(Packet.ByteArray.at(0)))); Lgc_Core_AppendPacketLog(p_State, QStringLiteral("收到"), Packet.PortName, Packet.ByteArray, ExplainText); } bool Lgc_Core_HandleFunctionButtons(Lgc_Core_Struct_State* p_State) { if (!p_State->IsPhysicalKeyStateValid) { p_State->LastPhysicalUsageList.clear(); return false; } if (p_State->IsFunctionSequenceRecording) { p_State->LastPhysicalUsageList = p_State->PhysicalUsageList; return false; } bool IsChanged = false; for (quint16 Usage : p_State->PhysicalUsageList) { if (p_State->LastPhysicalUsageList.contains(Usage) || !Lgc_FunctionButton_HasUsageFeature(p_State->FunctionButtonConfig, Usage)) { continue; } QString TextStatus; if (!Lgc_FunctionButton_RunBinding(p_State, Usage, &TextStatus) || TextStatus.isEmpty()) { continue; } p_State->TextFunctionStatus = TextStatus; Lgc_Core_AppendStatusLog(p_State, TextStatus); IsChanged = true; } p_State->LastPhysicalUsageList = p_State->PhysicalUsageList; return IsChanged; }