Files
Qt_keyboard/LOGIC/Lgc_Core_Input.cpp

373 lines
12 KiB
C++
Raw Permalink Normal View History

2026-04-03 09:26:10 +08:00
#include "LOGIC/Lgc_Core_Private.h"
#include "MID/Mid_Ble.h"
#include <QtCore/QDateTime>
#include <QtCore/QStringList>
#include <QtCore/QTimeZone>
#include <Windows.h>
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<quint16>* 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<quint8>(1U << (Usage % 8));
const quint8 ByteValue = static_cast<quint8>(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<quint8>(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<quint8>(Packet.ByteArray.at(0)) == Mid_Enum_ReportId_Nkro) &&
(Packet.ByteArray.size() == MID_CONST_PACKET_SIZE_NKRO))
{
const quint8 Modifier = static_cast<quint8>(Packet.ByteArray.at(1));
const QByteArray UsageBitmap = Packet.ByteArray.mid(2, MID_CONST_USAGE_BITMAP_SIZE);
QVector<quint16> 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<quint8>(Packet.ByteArray.at(0)) == Mid_Enum_ReportId_Consumer) &&
(Packet.ByteArray.size() == MID_CONST_PACKET_SIZE_CONSUMER))
{
const quint16 Usage =
static_cast<quint8>(Packet.ByteArray.at(1)) |
(static_cast<quint16>(static_cast<quint8>(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<quint8>(Packet.ByteArray.at(0));
if ((ReportId == Mid_Enum_ReportId_Vendor) && (Packet.ByteArray.size() == MID_CONST_PACKET_SIZE_VENDOR))
{
const quint8 Modifier = static_cast<quint8>(Packet.ByteArray.at(1));
const QByteArray UsageBitmap = Packet.ByteArray.mid(2, MID_CONST_USAGE_BITMAP_SIZE);
QVector<quint16> 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<quint8>(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<quint8>(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;
}