#include "LOGIC/Lgc_Core_Private.h" #include #include #include namespace { struct Lgc_Core_Struct_ThemeColor { quint8 Red; quint8 Green; quint8 Blue; }; QString Lgc_Core_FormatThemeColor(quint8 Red, quint8 Green, quint8 Blue) { return QStringLiteral("%1 %2 %3") .arg(Red, 2, 16, QLatin1Char('0')) .arg(Green, 2, 16, QLatin1Char('0')) .arg(Blue, 2, 16, QLatin1Char('0')) .toUpper(); } Lgc_Core_Struct_ThemeColor Lgc_Core_GetNextThemeColor(Lgc_Core_Struct_State* p_State) { p_State->IsAltThemeEnabled = !p_State->IsAltThemeEnabled; if (p_State->IsAltThemeEnabled) { return { 0xF7, 0x25, 0x85 }; } return { 0x4C, 0xC9, 0xF0 }; } bool Lgc_Core_IsUsageInRange(quint16 Usage) { return Usage <= MID_CONST_KEYBOARD_USAGE_MAX; } bool Lgc_Core_IsUsageEnabled(const QByteArray& Bitmap, quint16 Usage) { if (!Lgc_Core_IsUsageInRange(Usage) || (Bitmap.size() < MID_CONST_USAGE_BITMAP_SIZE)) { return true; } const int ByteIndex = Usage / 8; const quint8 BitMask = static_cast(1U << (Usage % 8)); const quint8 ByteValue = static_cast(Bitmap.at(ByteIndex)); return (ByteValue & BitMask) != 0; } void Lgc_Core_SetUsageEnabled(QByteArray* p_Bitmap, quint16 Usage, bool IsEnabled) { if (!Lgc_Core_IsUsageInRange(Usage)) { return; } if (p_Bitmap->size() < MID_CONST_USAGE_BITMAP_SIZE) { Lgc_Core_FillMaskAllEnabled(p_Bitmap); } const int ByteIndex = Usage / 8; const quint8 BitMask = static_cast(1U << (Usage % 8)); quint8 ByteValue = static_cast(p_Bitmap->at(ByteIndex)); if (IsEnabled) { ByteValue = static_cast(ByteValue | BitMask); } else { ByteValue = static_cast(ByteValue & ~BitMask); } (*p_Bitmap)[ByteIndex] = static_cast(ByteValue); } void Lgc_Core_RebuildKeyboardMask(Lgc_Core_Struct_State* p_State) { if (p_State->FunctionMaskBitmap.size() < MID_CONST_USAGE_BITMAP_SIZE) { Lgc_Core_FillMaskAllEnabled(&p_State->FunctionMaskBitmap); } p_State->KeyboardMaskBitmap.resize(MID_CONST_USAGE_BITMAP_SIZE); for (int Index = 0; Index < MID_CONST_USAGE_BITMAP_SIZE; ++Index) { p_State->KeyboardMaskBitmap[Index] = p_State->FunctionMaskBitmap.at(Index); } } QByteArray Lgc_Core_BuildMaskPacket(const Lgc_Core_Struct_State* p_State) { QByteArray Packet(MID_CONST_PACKET_SIZE_VENDOR, 0); Packet[0] = static_cast(Mid_Enum_ReportId_Vendor); for (int Index = 0; (Index < MID_CONST_USAGE_BITMAP_SIZE) && (Index < p_State->KeyboardMaskBitmap.size()); ++Index) { Packet[Index + 2] = p_State->KeyboardMaskBitmap.at(Index); } return Packet; } QByteArray Lgc_Core_BuildCommandPacket(quint8 CommandId, const QByteArray& Payload) { QByteArray Packet(MID_CONST_PACKET_SIZE_VENDOR_COMMAND, 0); Packet[0] = static_cast(Mid_Enum_ReportId_VendorCommand); Packet[1] = static_cast(CommandId); for (int Index = 0; (Index < MID_CONST_PACKET_SIZE_VENDOR_COMMAND_DATA) && (Index < Payload.size()); ++Index) { Packet[Index + 2] = Payload.at(Index); } return Packet; } bool Lgc_Core_SendPacket( Lgc_Core_Struct_State* p_State, const QByteArray& Packet, const QString& ExplainText) { QString RouteText; QString TextStatus; const auto AppendStatus = [&TextStatus](const QString& StatusText) { if (StatusText.isEmpty()) { return; } if (!TextStatus.isEmpty()) { TextStatus.append(QLatin1Char('\n')); } TextStatus.append(StatusText); }; const auto AppendRoute = [&RouteText](const QString& RouteName) { if (RouteName.isEmpty()) { return; } if (!RouteText.isEmpty()) { RouteText.append(QStringLiteral(" -> ")); } RouteText.append(RouteName); }; const auto TrySendUsb = [&]() -> bool { if (!p_State->DriVendorPort.ReadPort.IsOpened) { return false; } QString UsbStatus; const QString RouteName = p_State->DriVendorPort.ReadPort.PortName; if (Dri_Vendor_Write(&p_State->DriVendorPort, Packet, &UsbStatus)) { Lgc_Core_AppendPacketLog( p_State, QStringLiteral("发送"), RouteName, Packet, ExplainText); Lgc_Core_AppendStatusLog(p_State, UsbStatus); return true; } AppendRoute(RouteName); AppendStatus(UsbStatus); return false; }; const auto TrySendBle = [&]() -> bool { if (!p_State->DriBlePort.IsConnected) { return false; } QString BleStatus; if (Dri_Ble_Write(&p_State->DriBlePort, Packet, &BleStatus)) { Lgc_Core_AppendPacketLog( p_State, QStringLiteral("发送"), QStringLiteral("Bluetooth/HID Vendor"), Packet, ExplainText); Lgc_Core_AppendStatusLog(p_State, BleStatus); return true; } AppendRoute(QStringLiteral("Bluetooth/HID Vendor")); AppendStatus(BleStatus); return false; }; if (p_State->DriBlePort.IsConnected) { if (TrySendBle() || TrySendUsb()) { return true; } } else if (TrySendUsb()) { return true; } if (RouteText.isEmpty()) { RouteText = QStringLiteral("Vendor"); } if (TextStatus.isEmpty()) { TextStatus = QStringLiteral("No connected USB/Bluetooth device was found."); } Lgc_Core_AppendPacketLog( p_State, QStringLiteral("发送失败"), RouteText, Packet, ExplainText); Lgc_Core_AppendStatusLog(p_State, TextStatus); return false; } qint64 Lgc_Core_GetBeijingTimestampMs() { return QDateTime::currentDateTimeUtc() .toTimeZone(QTimeZone("Asia/Shanghai")) .toMSecsSinceEpoch() + (8LL * 60LL * 60LL * 1000LL); } QString Lgc_Core_GetBeijingTimeText(qint64 TimestampMs) { const QTimeZone BeijingTimeZone("Asia/Shanghai"); return QDateTime::fromMSecsSinceEpoch(TimestampMs, Qt::UTC) .toTimeZone(BeijingTimeZone) .toString(QStringLiteral("yyyy-MM-dd HH:mm:ss.zzz")); } } // namespace void Lgc_Core_FillMaskAllEnabled(QByteArray* p_UsageBitmap) { *p_UsageBitmap = QByteArray(MID_CONST_USAGE_BITMAP_SIZE, static_cast(0xFF)); } bool Lgc_Core_SendCurrentMask(Lgc_Core_Struct_State* p_State) { Lgc_Core_RebuildKeyboardMask(p_State); return Lgc_Core_SendPacket( p_State, Lgc_Core_BuildMaskPacket(p_State), QStringLiteral("0x04 键盘掩码同步")); } bool Lgc_Core_ApplyFunctionConfig(Lgc_Core_Struct_State* p_State) { Lgc_Core_FillMaskAllEnabled(&p_State->FunctionMaskBitmap); const QVector UsageList = Lgc_FunctionButton_GetConfigurableUsages(); for (quint16 Usage : UsageList) { if (Lgc_FunctionButton_HasUsageFeature(p_State->FunctionButtonConfig, Usage)) { Lgc_Core_SetUsageEnabled(&p_State->FunctionMaskBitmap, Usage, false); } } if (p_State->IsStarted && (p_State->DriVendorPort.ReadPort.IsOpened || p_State->DriBlePort.IsConnected)) { Lgc_Core_SendCurrentMask(p_State); } return true; } bool Lgc_Core_SendTimeSync(Lgc_Core_Struct_State* p_State) { const qint64 TimestampMs = Lgc_Core_GetBeijingTimestampMs(); QByteArray Payload(MID_CONST_PACKET_SIZE_VENDOR_COMMAND_DATA, 0); for (int Index = 0; Index < MID_CONST_PACKET_SIZE_VENDOR_COMMAND_DATA; ++Index) { Payload[Index] = static_cast((static_cast(TimestampMs) >> (Index * 8)) & 0xFF); } return Lgc_Core_SendPacket( p_State, Lgc_Core_BuildCommandPacket(0x02, Payload), QStringLiteral("0x05 0x02 时间同步(北京时间毫秒值:%1,北京时间:%2)") .arg(QString::number(TimestampMs), Lgc_Core_GetBeijingTimeText(TimestampMs))); } bool Lgc_Core_SendThemeSwitch(Lgc_Core_Struct_State* p_State) { const Lgc_Core_Struct_ThemeColor ThemeColor = Lgc_Core_GetNextThemeColor(p_State); QByteArray Payload(MID_CONST_PACKET_SIZE_VENDOR_COMMAND_DATA, 0); Payload[0] = static_cast(ThemeColor.Red); Payload[1] = static_cast(ThemeColor.Green); Payload[2] = static_cast(ThemeColor.Blue); return Lgc_Core_SendPacket( p_State, Lgc_Core_BuildCommandPacket(0x01, Payload), QStringLiteral("0x05 0x01 theme switch (RGB:%1)") .arg(Lgc_Core_FormatThemeColor( ThemeColor.Red, ThemeColor.Green, ThemeColor.Blue))); }