Files
Qt_keyboard/LOGIC/Lgc_Core_Control.cpp

321 lines
8.8 KiB
C++
Raw Normal View History

2026-04-03 09:26:10 +08:00
#include "LOGIC/Lgc_Core_Private.h"
#include <QtCore/QDateTime>
#include <QtCore/QStringList>
#include <QtCore/QTimeZone>
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<quint8>(1U << (Usage % 8));
const quint8 ByteValue = static_cast<quint8>(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<quint8>(1U << (Usage % 8));
quint8 ByteValue = static_cast<quint8>(p_Bitmap->at(ByteIndex));
if (IsEnabled)
{
ByteValue = static_cast<quint8>(ByteValue | BitMask);
}
else
{
ByteValue = static_cast<quint8>(ByteValue & ~BitMask);
}
(*p_Bitmap)[ByteIndex] = static_cast<char>(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<char>(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<char>(Mid_Enum_ReportId_VendorCommand);
Packet[1] = static_cast<char>(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<char>(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<quint16> 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<char>((static_cast<quint64>(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<char>(ThemeColor.Red);
Payload[1] = static_cast<char>(ThemeColor.Green);
Payload[2] = static_cast<char>(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)));
}