Files
Qt_keyboard/LOGIC/Lgc_Core_Control.cpp
2026-04-03 09:26:10 +08:00

321 lines
8.8 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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)));
}