first push

This commit is contained in:
2026-04-03 09:26:10 +08:00
parent 2937a44e07
commit 025b88e366
41 changed files with 6842 additions and 0 deletions

127
LOGIC/Lgc_Core.cpp Normal file
View File

@@ -0,0 +1,127 @@
#include "LOGIC/Lgc_Core_Private.h"
#include <Windows.h>
void Lgc_Core_Init(Lgc_Core_Struct_State* p_State)
{
*p_State = Lgc_Core_Struct_State();
p_State->DeviceConfig = Mid_Struct_DeviceConfig();
p_State->TextConnection = QStringLiteral("未连接,等待枚举设备。");
p_State->TextFunctionStatus = QStringLiteral("等待功能键动作。");
Lgc_Core_ClearAllKeyStates(p_State);
p_State->IsSystemNumLockOn = (GetKeyState(VK_NUMLOCK) & 0x0001) != 0;
Lgc_Core_FillMaskAllEnabled(&p_State->FunctionMaskBitmap);
Lgc_Core_FillMaskAllEnabled(&p_State->KeyboardMaskBitmap);
p_State->FunctionButtonConfig = Lgc_FunctionButton_Config();
Lgc_Core_ApplyFunctionConfig(p_State);
}
void Lgc_Core_SetWindowHandle(Lgc_Core_Struct_State* p_State, void* WindowHandle)
{
p_State->WindowHandle = WindowHandle;
}
void Lgc_Core_HandleNativeMessage(Lgc_Core_Struct_State* p_State, void* p_Message)
{
QString TextStatus;
Dri_NkroRaw_HandleMessage(&p_State->DriNkroPort, p_Message, &TextStatus);
Lgc_Core_AppendStatusLog(p_State, TextStatus);
}
void Lgc_Core_Start(Lgc_Core_Struct_State* p_State)
{
if (p_State->IsStarted)
{
return;
}
p_State->IsStarted = true;
Lgc_Core_RefreshDevice(p_State);
}
void Lgc_Core_Close(Lgc_Core_Struct_State* p_State)
{
Lgc_Core_CloseAllPorts(p_State);
p_State->TextConnection = QStringLiteral("未连接,等待枚举设备。");
p_State->TextFunctionStatus = QStringLiteral("等待功能键动作。");
p_State->ActiveSendTransport = Lgc_Core_Enum_SendTransport_None;
p_State->IsConnected = false;
p_State->IsStarted = false;
Lgc_Core_ClearAllKeyStates(p_State);
}
void Lgc_Core_RefreshDevice(Lgc_Core_Struct_State* p_State)
{
QString TextStatus;
Lgc_Core_CloseAllPorts(p_State);
Lgc_Core_ClearAllKeyStates(p_State);
TextStatus.clear();
Dri_NkroRaw_Init(&p_State->DriNkroPort, p_State->DeviceConfig, p_State->WindowHandle, &TextStatus);
Lgc_Core_AppendStatusLog(p_State, TextStatus);
TextStatus.clear();
Dri_Consumer_Init(&p_State->DriConsumerPort, p_State->DeviceConfig, &TextStatus);
Lgc_Core_AppendStatusLog(p_State, TextStatus);
TextStatus.clear();
Dri_Vendor_Init(&p_State->DriVendorPort, p_State->DeviceConfig, &TextStatus);
Lgc_Core_AppendStatusLog(p_State, TextStatus);
TextStatus.clear();
Dri_Ble_Init(&p_State->DriBlePort, p_State->DeviceConfig, &TextStatus);
Lgc_Core_AppendStatusLog(p_State, TextStatus);
Lgc_Core_NormalizeSendTransport(p_State);
Lgc_Core_SendCurrentMask(p_State);
if (p_State->DriVendorPort.ReadPort.IsOpened)
{
Lgc_Core_SendTimeSync(p_State);
}
Lgc_Core_SyncSystemState(p_State);
}
void Lgc_Core_ClearLog(Lgc_Core_Struct_State* p_State)
{
p_State->TextLog.clear();
}
bool Lgc_Core_Poll(Lgc_Core_Struct_State* p_State)
{
bool IsChanged = false;
Mid_Struct_RawPacket Packet;
const auto PollPort = [&](auto ReadFunc, auto HandleFunc, auto* p_Port)
{
QString TextStatus;
if (ReadFunc(p_Port, &Packet, &TextStatus))
{
HandleFunc(p_State, Packet);
IsChanged = true;
}
if (!TextStatus.isEmpty())
{
Lgc_Core_AppendStatusLog(p_State, TextStatus);
IsChanged = true;
}
};
PollPort(Dri_NkroRaw_Read, Lgc_Core_HandleNkroPacket, &p_State->DriNkroPort);
PollPort(Dri_Consumer_Read, Lgc_Core_HandleConsumerPacket, &p_State->DriConsumerPort);
PollPort(Dri_Vendor_Read, Lgc_Core_HandleVendorPacket, &p_State->DriVendorPort);
PollPort(Dri_Ble_Read, Lgc_Core_HandleBlePacket, &p_State->DriBlePort);
IsChanged |= Lgc_Core_HandleFunctionButtons(p_State);
IsChanged |= Lgc_Core_SyncSystemState(p_State);
return IsChanged;
}

65
LOGIC/Lgc_Core.h Normal file
View File

@@ -0,0 +1,65 @@
#pragma once
#include "DRI/Dri_Ble.h"
#include "DRI/Dri_Consumer.h"
#include "DRI/Dri_NkroRaw.h"
#include "DRI/Dri_Vendor.h"
#include "LOGIC/Lgc_Func_Button.h"
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QVector>
enum Lgc_Core_Enum_SendTransport : quint8
{
Lgc_Core_Enum_SendTransport_None = 0,
Lgc_Core_Enum_SendTransport_Usb,
Lgc_Core_Enum_SendTransport_Ble
};
struct Lgc_Core_Struct_State
{
Dri_Ble_Struct_Port DriBlePort;
Dri_NkroRaw_Struct_Port DriNkroPort;
Dri_Consumer_Struct_Port DriConsumerPort;
Dri_Vendor_Struct_Port DriVendorPort;
Mid_Struct_DeviceConfig DeviceConfig;
QString TextConnection;
QString TextLog;
QString TextFunctionStatus;
bool IsVisibleKeyStateValid = false;
QVector<quint16> VisibleUsageList;
bool IsPhysicalKeyStateValid = false;
QVector<quint16> PhysicalUsageList;
QVector<quint16> LastPhysicalUsageList;
bool IsSystemNumLockOn = false;
QByteArray FunctionMaskBitmap;
QByteArray KeyboardMaskBitmap;
Lgc_FunctionButton_Config FunctionButtonConfig;
bool IsAltThemeEnabled = false;
void* WindowHandle = nullptr;
bool IsConnected = false;
bool IsStarted = false;
Lgc_Core_Enum_SendTransport ActiveSendTransport = Lgc_Core_Enum_SendTransport_None;
bool IsFunctionSequenceRecording = false;
};
void Lgc_Core_Init(Lgc_Core_Struct_State* p_State);
void Lgc_Core_SetWindowHandle(Lgc_Core_Struct_State* p_State, void* WindowHandle);
void Lgc_Core_HandleNativeMessage(Lgc_Core_Struct_State* p_State, void* p_Message);
void Lgc_Core_Start(Lgc_Core_Struct_State* p_State);
void Lgc_Core_Close(Lgc_Core_Struct_State* p_State);
void Lgc_Core_RefreshDevice(Lgc_Core_Struct_State* p_State);
void Lgc_Core_ClearLog(Lgc_Core_Struct_State* p_State);
bool Lgc_Core_Poll(Lgc_Core_Struct_State* p_State);
bool Lgc_Core_ApplyFunctionConfig(Lgc_Core_Struct_State* p_State);
bool Lgc_Core_SendTimeSync(Lgc_Core_Struct_State* p_State);
bool Lgc_Core_SendThemeSwitch(Lgc_Core_Struct_State* p_State);

320
LOGIC/Lgc_Core_Control.cpp Normal file
View File

@@ -0,0 +1,320 @@
#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)));
}

372
LOGIC/Lgc_Core_Input.cpp Normal file
View File

@@ -0,0 +1,372 @@
#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;
}

30
LOGIC/Lgc_Core_Private.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include "LOGIC/Lgc_Core.h"
void Lgc_Core_AppendStatusLog(Lgc_Core_Struct_State* p_State, const QString& Text);
void Lgc_Core_AppendPacketLog(
Lgc_Core_Struct_State* p_State,
const QString& ActionText,
const QString& PortName,
const QByteArray& Packet,
const QString& ExplainText);
void Lgc_Core_ClearAllKeyStates(Lgc_Core_Struct_State* p_State);
void Lgc_Core_CloseAllPorts(Lgc_Core_Struct_State* p_State);
void Lgc_Core_FillMaskAllEnabled(QByteArray* p_UsageBitmap);
void Lgc_Core_UpdateSendTransportByPacket(
Lgc_Core_Struct_State* p_State,
Mid_Enum_RawPacketSource Source);
void Lgc_Core_NormalizeSendTransport(Lgc_Core_Struct_State* p_State);
bool Lgc_Core_SendCurrentMask(Lgc_Core_Struct_State* p_State);
bool Lgc_Core_SyncSystemState(Lgc_Core_Struct_State* p_State);
void Lgc_Core_HandleNkroPacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet);
void Lgc_Core_HandleConsumerPacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet);
void Lgc_Core_HandleVendorPacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet);
void Lgc_Core_HandleBlePacket(Lgc_Core_Struct_State* p_State, const Mid_Struct_RawPacket& Packet);
bool Lgc_Core_HandleFunctionButtons(Lgc_Core_Struct_State* p_State);

239
LOGIC/Lgc_Func_Button.cpp Normal file
View File

@@ -0,0 +1,239 @@
#include "LOGIC/Lgc_Func_Button.h"
#include "LOGIC/Lgc_Core.h"
#include "LOGIC/Lgc_Func_Button_Private.h"
#include "MID/Mid_Def.h"
#include <algorithm>
QString Lgc_FunctionButton_GetUsageShortText(quint16 Usage)
{
switch (Usage)
{
case 0x0053: return QStringLiteral("Num");
case 0x0054: return QStringLiteral("/");
case 0x0055: return QStringLiteral("*");
case 0x0056: return QStringLiteral("-");
case 0x0057: return QStringLiteral("+");
case 0x0058: return QStringLiteral("Enter");
case 0x0059: return QStringLiteral("1");
case 0x005A: return QStringLiteral("2");
case 0x005B: return QStringLiteral("3");
case 0x005C: return QStringLiteral("4");
case 0x005D: return QStringLiteral("5");
case 0x005E: return QStringLiteral("6");
case 0x005F: return QStringLiteral("7");
case 0x0060: return QStringLiteral("8");
case 0x0061: return QStringLiteral("9");
case 0x0062: return QStringLiteral("0");
case 0x0063: return QStringLiteral(".");
default:
return Mid_GetKeyboardUsageText(Usage);
}
}
QString Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type Type)
{
switch (Type)
{
case Lgc_FunctionFeature_Type::KeyCombination:
return QStringLiteral("快捷键");
case Lgc_FunctionFeature_Type::KeySequence:
return QStringLiteral("快捷键序列");
case Lgc_FunctionFeature_Type::Website:
return QStringLiteral("打开网址");
default:
return QStringLiteral("未知类型");
}
}
QVector<quint16> Lgc_FunctionButton_GetConfigurableUsages()
{
return {
0x0053, 0x0054, 0x0055, 0x0056,
0x005F, 0x0060, 0x0061, 0x0057,
0x005C, 0x005D, 0x005E,
0x0059, 0x005A, 0x005B, 0x0058,
0x0062, 0x0063
};
}
QVector<int> Lgc_FunctionButton_GetFeatureIdList(const Lgc_FunctionButton_Config& Config)
{
QVector<int> FeatureIdList = Config.FeatureMap.keys().toVector();
std::sort(FeatureIdList.begin(), FeatureIdList.end());
return FeatureIdList;
}
Lgc_FunctionFeature_Definition Lgc_FunctionButton_GetFeature(
const Lgc_FunctionButton_Config& Config,
int FeatureId)
{
return Config.FeatureMap.value(FeatureId);
}
QString Lgc_FunctionButton_GetFeatureName(const Lgc_FunctionFeature_Definition& Feature)
{
if (!Feature.Name.trimmed().isEmpty())
{
return Feature.Name.trimmed();
}
return Feature.Id > 0 ? QStringLiteral("功能%1").arg(Feature.Id) : QStringLiteral("未命名功能");
}
int Lgc_FunctionButton_AddFeature(Lgc_FunctionButton_Config* p_Config)
{
if (p_Config == nullptr)
{
return 0;
}
int FeatureId = 1;
while (p_Config->FeatureMap.contains(FeatureId))
{
++FeatureId;
}
p_Config->NextFeatureId = FeatureId + 1;
Lgc_FunctionFeature_Definition Feature;
Feature.Id = FeatureId;
Feature.Name = QStringLiteral("功能%1").arg(FeatureId);
Feature.Type = Lgc_FunctionFeature_Type::KeyCombination;
p_Config->FeatureMap.insert(FeatureId, Feature);
return FeatureId;
}
void Lgc_FunctionButton_RemoveFeature(Lgc_FunctionButton_Config* p_Config, int FeatureId)
{
if ((p_Config == nullptr) || (FeatureId <= 0))
{
return;
}
p_Config->FeatureMap.remove(FeatureId);
if (p_Config->FeatureMap.isEmpty())
{
p_Config->NextFeatureId = 1;
}
else if (FeatureId < p_Config->NextFeatureId)
{
p_Config->NextFeatureId = FeatureId;
}
auto It = p_Config->UsageFeatureIdMap.begin();
while (It != p_Config->UsageFeatureIdMap.end())
{
if (It.value() == FeatureId)
{
It = p_Config->UsageFeatureIdMap.erase(It);
}
else
{
++It;
}
}
}
void Lgc_FunctionButton_SetFeature(
Lgc_FunctionButton_Config* p_Config,
const Lgc_FunctionFeature_Definition& Feature)
{
if ((p_Config == nullptr) || (Feature.Id <= 0))
{
return;
}
p_Config->FeatureMap.insert(Feature.Id, Feature);
if (p_Config->NextFeatureId <= Feature.Id)
{
p_Config->NextFeatureId = Feature.Id + 1;
}
}
int Lgc_FunctionButton_GetUsageFeatureId(
const Lgc_FunctionButton_Config& Config,
quint16 Usage)
{
const int FeatureId = Config.UsageFeatureIdMap.value(Usage, 0);
return Config.FeatureMap.contains(FeatureId) ? FeatureId : 0;
}
void Lgc_FunctionButton_SetUsageFeatureId(
Lgc_FunctionButton_Config* p_Config,
quint16 Usage,
int FeatureId)
{
if (p_Config == nullptr)
{
return;
}
if ((FeatureId <= 0) || !p_Config->FeatureMap.contains(FeatureId))
{
p_Config->UsageFeatureIdMap.remove(Usage);
return;
}
p_Config->UsageFeatureIdMap.insert(Usage, FeatureId);
}
bool Lgc_FunctionButton_HasUsageFeature(
const Lgc_FunctionButton_Config& Config,
quint16 Usage)
{
return Lgc_FunctionButton_GetUsageFeatureId(Config, Usage) > 0;
}
bool Lgc_FunctionButton_SendUsageToWindows(quint16 Usage, bool IsPressed)
{
const Lgc_FunctionButton_Struct_WindowsKey Key = Lgc_FunctionButton_GetWindowsKey(Usage);
return Lgc_FunctionButton_SendWindowsKey(Key, IsPressed);
}
bool Lgc_FunctionButton_RunBinding(
Lgc_Core_Struct_State* p_State,
quint16 Usage,
QString* p_TextStatus)
{
if ((p_State == nullptr) || (p_TextStatus == nullptr))
{
return false;
}
*p_TextStatus = QString();
const int FeatureId =
Lgc_FunctionButton_GetUsageFeatureId(p_State->FunctionButtonConfig, Usage);
if (FeatureId <= 0)
{
return false;
}
const Lgc_FunctionFeature_Definition Feature =
Lgc_FunctionButton_GetFeature(p_State->FunctionButtonConfig, FeatureId);
if (Feature.Id <= 0)
{
return false;
}
switch (Feature.Type)
{
case Lgc_FunctionFeature_Type::KeyCombination:
Lgc_FunctionButton_RunKeyCombination(Feature, Usage, p_TextStatus);
return true;
case Lgc_FunctionFeature_Type::KeySequence:
Lgc_FunctionButton_RunKeySequence(Feature, Usage, p_TextStatus);
return true;
case Lgc_FunctionFeature_Type::Website:
Lgc_FunctionButton_RunOpenWebsite(Feature, p_TextStatus);
return true;
default:
*p_TextStatus = QStringLiteral("%1 绑定了未知功能。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
return true;
}
}

62
LOGIC/Lgc_Func_Button.h Normal file
View File

@@ -0,0 +1,62 @@
#pragma once
#include "MID/Mid_Def.h"
#include <QtCore/QHash>
#include <QtCore/QString>
#include <QtCore/QVector>
struct Lgc_Core_Struct_State;
enum class Lgc_FunctionFeature_Type : quint8
{
KeyCombination = 0,
KeySequence = 1,
Website = 2
};
struct Lgc_FunctionFeature_Definition
{
int Id = 0;
QString Name;
QString Description;
Lgc_FunctionFeature_Type Type = Lgc_FunctionFeature_Type::KeyCombination;
QString SequenceText;
QString WebsiteUrl;
};
struct Lgc_FunctionButton_Config
{
QHash<int, Lgc_FunctionFeature_Definition> FeatureMap;
QHash<quint16, int> UsageFeatureIdMap;
int NextFeatureId = 1;
};
QString Lgc_FunctionButton_GetUsageShortText(quint16 Usage);
QString Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type Type);
QVector<quint16> Lgc_FunctionButton_GetConfigurableUsages();
QVector<int> Lgc_FunctionButton_GetFeatureIdList(const Lgc_FunctionButton_Config& Config);
Lgc_FunctionFeature_Definition Lgc_FunctionButton_GetFeature(
const Lgc_FunctionButton_Config& Config,
int FeatureId);
QString Lgc_FunctionButton_GetFeatureName(const Lgc_FunctionFeature_Definition& Feature);
int Lgc_FunctionButton_AddFeature(Lgc_FunctionButton_Config* p_Config);
void Lgc_FunctionButton_RemoveFeature(Lgc_FunctionButton_Config* p_Config, int FeatureId);
void Lgc_FunctionButton_SetFeature(
Lgc_FunctionButton_Config* p_Config,
const Lgc_FunctionFeature_Definition& Feature);
int Lgc_FunctionButton_GetUsageFeatureId(
const Lgc_FunctionButton_Config& Config,
quint16 Usage);
void Lgc_FunctionButton_SetUsageFeatureId(
Lgc_FunctionButton_Config* p_Config,
quint16 Usage,
int FeatureId);
bool Lgc_FunctionButton_HasUsageFeature(
const Lgc_FunctionButton_Config& Config,
quint16 Usage);
bool Lgc_FunctionButton_SendUsageToWindows(quint16 Usage, bool IsPressed);
bool Lgc_FunctionButton_RunBinding(
Lgc_Core_Struct_State* p_State,
quint16 Usage,
QString* p_TextStatus);

View File

@@ -0,0 +1,573 @@
#include "LOGIC/Lgc_Func_Button_Private.h"
#include <QtCore/QRegularExpression>
#include <QtCore/QStringList>
namespace
{
bool Lgc_FunctionButton_IsSequenceSeparator(QChar Character)
{
return Character.isSpace() ||
(Character == QLatin1Char(',')) ||
(Character == QLatin1Char(';')) ||
(Character == QLatin1Char('|')) ||
(Character == QChar(0xFF0C)) ||
(Character == QChar(0xFF1B)) ||
(Character == QChar(0x3001));
}
quint16 Lgc_FunctionButton_GetUsageFromDigit(QChar Character)
{
switch (Character.unicode())
{
case '0': return 0x0062;
case '1': return 0x0059;
case '2': return 0x005A;
case '3': return 0x005B;
case '4': return 0x005C;
case '5': return 0x005D;
case '6': return 0x005E;
case '7': return 0x005F;
case '8': return 0x0060;
case '9': return 0x0061;
default:
return 0;
}
}
quint16 Lgc_FunctionButton_GetUsageFromSymbol(QChar Character)
{
switch (Character.unicode())
{
case '+': return 0x0057;
case '/': return 0x0054;
case '*': return 0x0055;
case '-': return 0x0056;
case '.': return 0x0063;
default:
return 0;
}
}
} // namespace
bool Lgc_FunctionButton_ParseLegacySequenceText(
const QString& Text,
quint16 SourceUsage,
QVector<quint16>* p_UsageList,
QString* p_ErrorText)
{
p_UsageList->clear();
if (p_ErrorText != nullptr) p_ErrorText->clear();
const QString UpperText = Text.toUpper();
int Index = 0;
const QVector<QPair<QString, quint16>> TokenList = {
{ QStringLiteral("NUMLOCK"), 0x0053 },
{ QStringLiteral("ENTER"), 0x0058 },
{ QStringLiteral("DIVIDE"), 0x0054 },
{ QStringLiteral("SLASH"), 0x0054 },
{ QStringLiteral("MULTIPLY"), 0x0055 },
{ QStringLiteral("ASTERISK"), 0x0055 },
{ QStringLiteral("DECIMAL"), 0x0063 },
{ QStringLiteral("MINUS"), 0x0056 },
{ QStringLiteral("SOURCE"), SourceUsage },
{ QStringLiteral("PLUS"), 0x0057 },
{ QStringLiteral("STAR"), 0x0055 },
{ QStringLiteral("SELF"), SourceUsage },
{ QStringLiteral("DOT"), 0x0063 },
{ QStringLiteral("NUM"), 0x0053 }
};
while (Index < Text.size())
{
const QChar Character = Text.at(Index);
if (Lgc_FunctionButton_IsSequenceSeparator(Character))
{
++Index;
continue;
}
if ((Index + 1) < Text.size())
{
const QString Token = Text.mid(Index, 2);
if ((Token == QStringLiteral("本键")) || (Token == QStringLiteral("自身")))
{
p_UsageList->append(SourceUsage);
Index += 2;
continue;
}
}
const quint16 DigitUsage = Lgc_FunctionButton_GetUsageFromDigit(Character);
if (DigitUsage != 0)
{
p_UsageList->append(DigitUsage);
++Index;
continue;
}
const quint16 SymbolUsage = Lgc_FunctionButton_GetUsageFromSymbol(Character);
if (SymbolUsage != 0)
{
p_UsageList->append(SymbolUsage);
++Index;
continue;
}
bool IsMatched = false;
for (const auto& Token : TokenList)
{
if (!UpperText.mid(Index, Token.first.size()).compare(Token.first, Qt::CaseInsensitive))
{
p_UsageList->append(Token.second);
Index += Token.first.size();
IsMatched = true;
break;
}
}
if (IsMatched)
{
continue;
}
if (p_ErrorText != nullptr)
{
*p_ErrorText = QStringLiteral("无法识别的按键序列片段:%1").arg(Text.mid(Index, 8));
}
p_UsageList->clear();
return false;
}
return true;
}
bool Lgc_FunctionButton_TryParseSequenceToken(
const QString& Token,
quint16 SourceUsage,
Lgc_FunctionButton_Struct_SequenceKey* p_KeyItem)
{
const QString TrimmedToken = Token.trimmed();
const QString UpperToken = TrimmedToken.toUpper();
if (UpperToken.isEmpty())
{
return false;
}
const auto SetKey = [p_KeyItem](WORD VirtualKey, DWORD ExtraFlags, bool IsModifier, const QString& Text)
{
p_KeyItem->Key = { VirtualKey, ExtraFlags, IsModifier };
p_KeyItem->Text = Text;
};
if ((UpperToken == QStringLiteral("SOURCE")) ||
(UpperToken == QStringLiteral("SELF")) ||
(TrimmedToken == QStringLiteral("本键")) ||
(TrimmedToken == QStringLiteral("自身")))
{
const auto SourceKey = Lgc_FunctionButton_GetWindowsKey(SourceUsage);
if (SourceKey.VirtualKey == 0)
{
return false;
}
p_KeyItem->Key = SourceKey;
p_KeyItem->Text = Lgc_FunctionButton_GetUsageShortText(SourceUsage);
return true;
}
if ((UpperToken.size() == 1) && UpperToken.at(0).isLetterOrNumber())
{
SetKey(static_cast<WORD>(UpperToken.at(0).unicode()), 0, false, UpperToken);
return true;
}
if (UpperToken == QStringLiteral("CTRL") || UpperToken == QStringLiteral("CONTROL"))
{
SetKey(VK_CONTROL, 0, true, QStringLiteral("Ctrl"));
return true;
}
if (UpperToken == QStringLiteral("SHIFT"))
{
SetKey(VK_SHIFT, 0, true, QStringLiteral("Shift"));
return true;
}
if (UpperToken == QStringLiteral("ALT"))
{
SetKey(VK_MENU, 0, true, QStringLiteral("Alt"));
return true;
}
if (UpperToken == QStringLiteral("WIN") || UpperToken == QStringLiteral("META"))
{
SetKey(VK_LWIN, 0, true, QStringLiteral("Win"));
return true;
}
if (UpperToken == QStringLiteral("ENTER"))
{
SetKey(VK_RETURN, 0, false, QStringLiteral("Enter"));
return true;
}
if (UpperToken == QStringLiteral("NUMENTER"))
{
SetKey(VK_RETURN, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("NumEnter"));
return true;
}
if (UpperToken == QStringLiteral("SPACE"))
{
SetKey(VK_SPACE, 0, false, QStringLiteral("Space"));
return true;
}
if (UpperToken == QStringLiteral("TAB"))
{
SetKey(VK_TAB, 0, false, QStringLiteral("Tab"));
return true;
}
if (UpperToken == QStringLiteral("ESC") || UpperToken == QStringLiteral("ESCAPE"))
{
SetKey(VK_ESCAPE, 0, false, QStringLiteral("Esc"));
return true;
}
if (UpperToken == QStringLiteral("BACKSPACE"))
{
SetKey(VK_BACK, 0, false, QStringLiteral("Backspace"));
return true;
}
if (UpperToken == QStringLiteral("DELETE"))
{
SetKey(VK_DELETE, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("Delete"));
return true;
}
if (UpperToken == QStringLiteral("INSERT"))
{
SetKey(VK_INSERT, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("Insert"));
return true;
}
if (UpperToken == QStringLiteral("HOME"))
{
SetKey(VK_HOME, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("Home"));
return true;
}
if (UpperToken == QStringLiteral("END"))
{
SetKey(VK_END, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("End"));
return true;
}
if (UpperToken == QStringLiteral("PAGEUP"))
{
SetKey(VK_PRIOR, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("PageUp"));
return true;
}
if (UpperToken == QStringLiteral("PAGEDOWN"))
{
SetKey(VK_NEXT, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("PageDown"));
return true;
}
if (UpperToken == QStringLiteral("LEFT"))
{
SetKey(VK_LEFT, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("Left"));
return true;
}
if (UpperToken == QStringLiteral("RIGHT"))
{
SetKey(VK_RIGHT, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("Right"));
return true;
}
if (UpperToken == QStringLiteral("UP"))
{
SetKey(VK_UP, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("Up"));
return true;
}
if (UpperToken == QStringLiteral("DOWN"))
{
SetKey(VK_DOWN, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("Down"));
return true;
}
if (UpperToken == QStringLiteral("CAPSLOCK"))
{
SetKey(VK_CAPITAL, 0, false, QStringLiteral("CapsLock"));
return true;
}
if (UpperToken == QStringLiteral("PRINTSCREEN"))
{
SetKey(VK_SNAPSHOT, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("PrintScreen"));
return true;
}
if (UpperToken == QStringLiteral("SCROLLLOCK"))
{
SetKey(VK_SCROLL, 0, false, QStringLiteral("ScrollLock"));
return true;
}
if (UpperToken == QStringLiteral("PAUSE"))
{
SetKey(VK_PAUSE, 0, false, QStringLiteral("Pause"));
return true;
}
if (UpperToken == QStringLiteral("NUM0")) { SetKey(VK_NUMPAD0, 0, false, QStringLiteral("Num0")); return true; }
if (UpperToken == QStringLiteral("NUM1")) { SetKey(VK_NUMPAD1, 0, false, QStringLiteral("Num1")); return true; }
if (UpperToken == QStringLiteral("NUM2")) { SetKey(VK_NUMPAD2, 0, false, QStringLiteral("Num2")); return true; }
if (UpperToken == QStringLiteral("NUM3")) { SetKey(VK_NUMPAD3, 0, false, QStringLiteral("Num3")); return true; }
if (UpperToken == QStringLiteral("NUM4")) { SetKey(VK_NUMPAD4, 0, false, QStringLiteral("Num4")); return true; }
if (UpperToken == QStringLiteral("NUM5")) { SetKey(VK_NUMPAD5, 0, false, QStringLiteral("Num5")); return true; }
if (UpperToken == QStringLiteral("NUM6")) { SetKey(VK_NUMPAD6, 0, false, QStringLiteral("Num6")); return true; }
if (UpperToken == QStringLiteral("NUM7")) { SetKey(VK_NUMPAD7, 0, false, QStringLiteral("Num7")); return true; }
if (UpperToken == QStringLiteral("NUM8")) { SetKey(VK_NUMPAD8, 0, false, QStringLiteral("Num8")); return true; }
if (UpperToken == QStringLiteral("NUM9")) { SetKey(VK_NUMPAD9, 0, false, QStringLiteral("Num9")); return true; }
if (UpperToken == QStringLiteral("NUM/")) { SetKey(VK_DIVIDE, KEYEVENTF_EXTENDEDKEY, false, QStringLiteral("Num/")); return true; }
if (UpperToken == QStringLiteral("NUM*")) { SetKey(VK_MULTIPLY, 0, false, QStringLiteral("Num*")); return true; }
if (UpperToken == QStringLiteral("NUM-")) { SetKey(VK_SUBTRACT, 0, false, QStringLiteral("Num-")); return true; }
if (UpperToken == QStringLiteral("NUM+")) { SetKey(VK_ADD, 0, false, QStringLiteral("Num+")); return true; }
if (UpperToken == QStringLiteral("NUM.")) { SetKey(VK_DECIMAL, 0, false, QStringLiteral("Num.")); return true; }
if (UpperToken == QStringLiteral("COMMA")) { SetKey(VK_OEM_COMMA, 0, false, QStringLiteral("Comma")); return true; }
if (UpperToken == QStringLiteral("PERIOD")) { SetKey(VK_OEM_PERIOD, 0, false, QStringLiteral("Period")); return true; }
if (UpperToken == QStringLiteral("SEMICOLON")) { SetKey(VK_OEM_1, 0, false, QStringLiteral("Semicolon")); return true; }
if (UpperToken == QStringLiteral("SLASH")) { SetKey(VK_OEM_2, 0, false, QStringLiteral("Slash")); return true; }
if (UpperToken == QStringLiteral("GRAVE")) { SetKey(VK_OEM_3, 0, false, QStringLiteral("Grave")); return true; }
if (UpperToken == QStringLiteral("LEFTBRACKET")) { SetKey(VK_OEM_4, 0, false, QStringLiteral("LeftBracket")); return true; }
if (UpperToken == QStringLiteral("BACKSLASH")) { SetKey(VK_OEM_5, 0, false, QStringLiteral("Backslash")); return true; }
if (UpperToken == QStringLiteral("RIGHTBRACKET")) { SetKey(VK_OEM_6, 0, false, QStringLiteral("RightBracket")); return true; }
if (UpperToken == QStringLiteral("QUOTE")) { SetKey(VK_OEM_7, 0, false, QStringLiteral("Quote")); return true; }
if (UpperToken == QStringLiteral("MINUS")) { SetKey(VK_OEM_MINUS, 0, false, QStringLiteral("Minus")); return true; }
if (UpperToken == QStringLiteral("EQUAL")) { SetKey(VK_OEM_PLUS, 0, false, QStringLiteral("Equal")); return true; }
const QRegularExpression FunctionKeyPattern(QStringLiteral("^F(\\d{1,2})$"));
const QRegularExpressionMatch Match = FunctionKeyPattern.match(UpperToken);
if (Match.hasMatch())
{
const int FunctionIndex = Match.captured(1).toInt();
if ((FunctionIndex >= 1) && (FunctionIndex <= 24))
{
SetKey(
static_cast<WORD>(VK_F1 + FunctionIndex - 1),
0,
false,
QStringLiteral("F%1").arg(FunctionIndex));
return true;
}
}
return false;
}
bool Lgc_FunctionButton_ParseRecordedSequenceText(
const QString& Text,
quint16 SourceUsage,
QVector<Lgc_FunctionButton_Struct_SequenceKey>* p_KeyList,
QString* p_ErrorText)
{
p_KeyList->clear();
if (p_ErrorText != nullptr) p_ErrorText->clear();
const QStringList TokenList = Text.split(
QRegularExpression(QStringLiteral("[\\s,;|,;、]+")),
QString::SkipEmptyParts);
if (TokenList.isEmpty())
{
return false;
}
for (const QString& Token : TokenList)
{
Lgc_FunctionButton_Struct_SequenceKey KeyItem;
if (!Lgc_FunctionButton_TryParseSequenceToken(Token, SourceUsage, &KeyItem))
{
if (p_ErrorText != nullptr)
{
*p_ErrorText = QStringLiteral("无法识别的按键序列片段:%1").arg(Token);
}
p_KeyList->clear();
return false;
}
p_KeyList->append(KeyItem);
}
return true;
}
bool Lgc_FunctionButton_IsSameWindowsKey(
const Lgc_FunctionButton_Struct_WindowsKey& Left,
const Lgc_FunctionButton_Struct_WindowsKey& Right)
{
return (Left.VirtualKey == Right.VirtualKey) &&
(Left.ExtraFlags == Right.ExtraFlags);
}
bool Lgc_FunctionButton_ParseKeyCombinationText(
const QString& Text,
quint16 SourceUsage,
QVector<Lgc_FunctionButton_Struct_SequenceKey>* p_KeyList,
QString* p_ErrorText)
{
p_KeyList->clear();
if (p_ErrorText != nullptr) p_ErrorText->clear();
QStringList TokenList;
if (Text.contains(QLatin1Char('+')))
{
TokenList = Text.split(
QRegularExpression(QStringLiteral("\\s*\\+\\s*")),
QString::SkipEmptyParts);
}
else
{
TokenList = Text.split(
QRegularExpression(QStringLiteral("[\\s,;|,;、]+")),
QString::SkipEmptyParts);
}
for (const QString& Token : TokenList)
{
Lgc_FunctionButton_Struct_SequenceKey KeyItem;
if (!Lgc_FunctionButton_TryParseSequenceToken(Token, SourceUsage, &KeyItem))
{
if (p_ErrorText != nullptr)
{
*p_ErrorText = QStringLiteral("无法识别的按键片段:%1").arg(Token);
}
p_KeyList->clear();
return false;
}
p_KeyList->append(KeyItem);
}
return !p_KeyList->isEmpty();
}
QString Lgc_FunctionButton_FormatKeyCombination(
const QVector<Lgc_FunctionButton_Struct_SequenceKey>& KeyList)
{
QStringList TextList;
for (const auto& KeyItem : KeyList)
{
TextList.append(KeyItem.Text);
}
return TextList.join(QStringLiteral("+"));
}
QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>>
Lgc_FunctionButton_GroupSequenceKeysIntoCombinations(
const QVector<Lgc_FunctionButton_Struct_SequenceKey>& KeyList)
{
QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>> CombinationList;
QVector<Lgc_FunctionButton_Struct_SequenceKey> ModifierList;
for (const auto& KeyItem : KeyList)
{
if (KeyItem.Key.IsModifier)
{
bool IsDuplicate = false;
for (const auto& OldModifier : ModifierList)
{
if (Lgc_FunctionButton_IsSameWindowsKey(OldModifier.Key, KeyItem.Key))
{
IsDuplicate = true;
break;
}
}
if (!IsDuplicate)
{
ModifierList.append(KeyItem);
}
continue;
}
QVector<Lgc_FunctionButton_Struct_SequenceKey> Combination = ModifierList;
Combination.append(KeyItem);
CombinationList.append(Combination);
}
if (CombinationList.isEmpty() && !ModifierList.isEmpty())
{
CombinationList.append(ModifierList);
}
return CombinationList;
}
bool Lgc_FunctionButton_ParseShortcutSequenceText(
const QString& Text,
quint16 SourceUsage,
QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>>* p_CombinationList,
QString* p_ErrorText)
{
p_CombinationList->clear();
if (p_ErrorText != nullptr) p_ErrorText->clear();
const QStringList SegmentList = Text.split(
QRegularExpression(QStringLiteral("\\s*(?:->|=>|→)\\s*")),
QString::SkipEmptyParts);
if (SegmentList.size() > 1)
{
for (const QString& SegmentText : SegmentList)
{
QVector<Lgc_FunctionButton_Struct_SequenceKey> Combination;
if (!Lgc_FunctionButton_ParseKeyCombinationText(
SegmentText,
SourceUsage,
&Combination,
p_ErrorText))
{
p_CombinationList->clear();
return false;
}
p_CombinationList->append(Combination);
}
return !p_CombinationList->isEmpty();
}
QVector<Lgc_FunctionButton_Struct_SequenceKey> FlatKeyList;
if (!Lgc_FunctionButton_ParseRecordedSequenceText(
Text,
SourceUsage,
&FlatKeyList,
p_ErrorText))
{
QVector<Lgc_FunctionButton_Struct_SequenceKey> SingleCombination;
if (!Lgc_FunctionButton_ParseKeyCombinationText(
Text,
SourceUsage,
&SingleCombination,
p_ErrorText))
{
return false;
}
p_CombinationList->append(SingleCombination);
return true;
}
*p_CombinationList = Lgc_FunctionButton_GroupSequenceKeysIntoCombinations(FlatKeyList);
return !p_CombinationList->isEmpty();
}
QString Lgc_FunctionButton_FormatShortcutSequence(
const QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>>& CombinationList)
{
QStringList TextList;
for (const auto& Combination : CombinationList)
{
TextList.append(Lgc_FunctionButton_FormatKeyCombination(Combination));
}
return TextList.join(QStringLiteral(" -> "));
}
QVector<Lgc_FunctionButton_Struct_SequenceKey> Lgc_FunctionButton_ConvertUsageListToSequenceKeys(
const QVector<quint16>& UsageList)
{
QVector<Lgc_FunctionButton_Struct_SequenceKey> KeyList;
for (quint16 Usage : UsageList)
{
const auto Key = Lgc_FunctionButton_GetWindowsKey(Usage);
if (Key.VirtualKey == 0)
{
KeyList.clear();
return KeyList;
}
Lgc_FunctionButton_Struct_SequenceKey KeyItem;
KeyItem.Key = Key;
KeyItem.Text = Lgc_FunctionButton_GetUsageShortText(Usage);
KeyList.append(KeyItem);
}
return KeyList;
}

View File

@@ -0,0 +1,76 @@
#pragma once
#include "LOGIC/Lgc_Func_Button.h"
#include <QtCore/QVector>
#include <Windows.h>
struct Lgc_FunctionButton_Struct_WindowsKey
{
WORD VirtualKey = 0;
DWORD ExtraFlags = 0;
bool IsModifier = false;
};
struct Lgc_FunctionButton_Struct_SequenceKey
{
Lgc_FunctionButton_Struct_WindowsKey Key;
QString Text;
};
Lgc_FunctionButton_Struct_WindowsKey Lgc_FunctionButton_GetWindowsKey(quint16 Usage);
bool Lgc_FunctionButton_SendWindowsKey(
const Lgc_FunctionButton_Struct_WindowsKey& Key,
bool IsPressed);
bool Lgc_FunctionButton_IsSameWindowsKey(
const Lgc_FunctionButton_Struct_WindowsKey& Left,
const Lgc_FunctionButton_Struct_WindowsKey& Right);
bool Lgc_FunctionButton_ParseLegacySequenceText(
const QString& Text,
quint16 SourceUsage,
QVector<quint16>* p_UsageList,
QString* p_ErrorText);
bool Lgc_FunctionButton_TryParseSequenceToken(
const QString& Token,
quint16 SourceUsage,
Lgc_FunctionButton_Struct_SequenceKey* p_KeyItem);
bool Lgc_FunctionButton_ParseRecordedSequenceText(
const QString& Text,
quint16 SourceUsage,
QVector<Lgc_FunctionButton_Struct_SequenceKey>* p_KeyList,
QString* p_ErrorText);
bool Lgc_FunctionButton_ParseKeyCombinationText(
const QString& Text,
quint16 SourceUsage,
QVector<Lgc_FunctionButton_Struct_SequenceKey>* p_KeyList,
QString* p_ErrorText);
QString Lgc_FunctionButton_FormatKeyCombination(
const QVector<Lgc_FunctionButton_Struct_SequenceKey>& KeyList);
QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>>
Lgc_FunctionButton_GroupSequenceKeysIntoCombinations(
const QVector<Lgc_FunctionButton_Struct_SequenceKey>& KeyList);
bool Lgc_FunctionButton_ParseShortcutSequenceText(
const QString& Text,
quint16 SourceUsage,
QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>>* p_CombinationList,
QString* p_ErrorText);
QString Lgc_FunctionButton_FormatShortcutSequence(
const QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>>& CombinationList);
QVector<Lgc_FunctionButton_Struct_SequenceKey> Lgc_FunctionButton_ConvertUsageListToSequenceKeys(
const QVector<quint16>& UsageList);
bool Lgc_FunctionButton_SendKeyCombination(
const QVector<Lgc_FunctionButton_Struct_SequenceKey>& KeyList);
bool Lgc_FunctionButton_SendShortcutSequence(
const QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>>& CombinationList);
void Lgc_FunctionButton_RunKeyCombination(
const Lgc_FunctionFeature_Definition& Feature,
quint16 SourceUsage,
QString* p_TextStatus);
void Lgc_FunctionButton_RunKeySequence(
const Lgc_FunctionFeature_Definition& Feature,
quint16 SourceUsage,
QString* p_TextStatus);
void Lgc_FunctionButton_RunOpenWebsite(
const Lgc_FunctionFeature_Definition& Feature,
QString* p_TextStatus);

View File

@@ -0,0 +1,302 @@
#include "LOGIC/Lgc_Func_Button_Private.h"
#include <QtCore/QUrl>
#include <QtGui/QDesktopServices>
#include <Windows.h>
namespace
{
constexpr DWORD LGC_FUNCTIONBUTTON_KEY_HOLD_DELAY_MS = 12;
constexpr DWORD LGC_FUNCTIONBUTTON_SEQUENCE_STEP_DELAY_MS = 60;
} // namespace
Lgc_FunctionButton_Struct_WindowsKey Lgc_FunctionButton_GetWindowsKey(quint16 Usage)
{
switch (Usage)
{
case 0x0053: return { VK_NUMLOCK, 0 };
case 0x0054: return { VK_DIVIDE, KEYEVENTF_EXTENDEDKEY };
case 0x0055: return { VK_MULTIPLY, 0 };
case 0x0056: return { VK_SUBTRACT, 0 };
case 0x0057: return { VK_ADD, 0 };
case 0x0058: return { VK_RETURN, KEYEVENTF_EXTENDEDKEY };
case 0x0059: return { VK_NUMPAD1, 0 };
case 0x005A: return { VK_NUMPAD2, 0 };
case 0x005B: return { VK_NUMPAD3, 0 };
case 0x005C: return { VK_NUMPAD4, 0 };
case 0x005D: return { VK_NUMPAD5, 0 };
case 0x005E: return { VK_NUMPAD6, 0 };
case 0x005F: return { VK_NUMPAD7, 0 };
case 0x0060: return { VK_NUMPAD8, 0 };
case 0x0061: return { VK_NUMPAD9, 0 };
case 0x0062: return { VK_NUMPAD0, 0 };
case 0x0063: return { VK_DECIMAL, 0 };
case 0x00E0: return { VK_CONTROL, 0, true };
case 0x00E1: return { VK_SHIFT, 0, true };
case 0x00E2: return { VK_MENU, 0, true };
case 0x00E3: return { VK_LWIN, 0, true };
case 0x00E4: return { VK_CONTROL, KEYEVENTF_EXTENDEDKEY, true };
case 0x00E5: return { VK_SHIFT, 0, true };
case 0x00E6: return { VK_MENU, KEYEVENTF_EXTENDEDKEY, true };
case 0x00E7: return { VK_RWIN, 0, true };
default:
return {};
}
}
bool Lgc_FunctionButton_SendWindowsKey(
const Lgc_FunctionButton_Struct_WindowsKey& Key,
bool IsPressed)
{
if (Key.VirtualKey == 0)
{
return false;
}
INPUT InputData = {};
InputData.type = INPUT_KEYBOARD;
InputData.ki.wVk = Key.VirtualKey;
InputData.ki.dwFlags = Key.ExtraFlags;
if (!IsPressed)
{
InputData.ki.dwFlags |= KEYEVENTF_KEYUP;
}
return SendInput(1, &InputData, sizeof(INPUT)) == 1;
}
bool Lgc_FunctionButton_SendKeyCombination(
const QVector<Lgc_FunctionButton_Struct_SequenceKey>& KeyList)
{
QVector<Lgc_FunctionButton_Struct_WindowsKey> ModifierList;
QVector<Lgc_FunctionButton_Struct_WindowsKey> NormalKeyList;
for (const auto& KeyItem : KeyList)
{
if (KeyItem.Key.VirtualKey == 0)
{
return false;
}
if (KeyItem.Key.IsModifier)
{
bool IsDuplicate = false;
for (const auto& OldModifier : ModifierList)
{
if (Lgc_FunctionButton_IsSameWindowsKey(OldModifier, KeyItem.Key))
{
IsDuplicate = true;
break;
}
}
if (!IsDuplicate)
{
ModifierList.append(KeyItem.Key);
}
continue;
}
NormalKeyList.append(KeyItem.Key);
}
for (int ModifierIndex = 0; ModifierIndex < ModifierList.size(); ++ModifierIndex)
{
const auto& ModifierKey = ModifierList.at(ModifierIndex);
if (!Lgc_FunctionButton_SendWindowsKey(ModifierKey, true))
{
for (int Index = ModifierIndex - 1; Index >= 0; --Index)
{
Lgc_FunctionButton_SendWindowsKey(ModifierList.at(Index), false);
}
return false;
}
Sleep(LGC_FUNCTIONBUTTON_KEY_HOLD_DELAY_MS);
}
if (NormalKeyList.isEmpty())
{
for (int Index = ModifierList.size() - 1; Index >= 0; --Index)
{
if (!Lgc_FunctionButton_SendWindowsKey(ModifierList.at(Index), false))
{
return false;
}
Sleep(LGC_FUNCTIONBUTTON_KEY_HOLD_DELAY_MS);
}
return !ModifierList.isEmpty();
}
for (const auto& NormalKey : NormalKeyList)
{
if (!Lgc_FunctionButton_SendWindowsKey(NormalKey, true))
{
for (int Index = ModifierList.size() - 1; Index >= 0; --Index)
{
Lgc_FunctionButton_SendWindowsKey(ModifierList.at(Index), false);
}
return false;
}
Sleep(LGC_FUNCTIONBUTTON_KEY_HOLD_DELAY_MS);
if (!Lgc_FunctionButton_SendWindowsKey(NormalKey, false))
{
for (int Index = ModifierList.size() - 1; Index >= 0; --Index)
{
Lgc_FunctionButton_SendWindowsKey(ModifierList.at(Index), false);
}
return false;
}
Sleep(LGC_FUNCTIONBUTTON_KEY_HOLD_DELAY_MS);
}
for (int Index = ModifierList.size() - 1; Index >= 0; --Index)
{
if (!Lgc_FunctionButton_SendWindowsKey(ModifierList.at(Index), false))
{
return false;
}
Sleep(LGC_FUNCTIONBUTTON_KEY_HOLD_DELAY_MS);
}
return true;
}
bool Lgc_FunctionButton_SendShortcutSequence(
const QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>>& CombinationList)
{
for (int Index = 0; Index < CombinationList.size(); ++Index)
{
const auto& Combination = CombinationList.at(Index);
if (!Lgc_FunctionButton_SendKeyCombination(Combination))
{
return false;
}
if (Index + 1 < CombinationList.size())
{
Sleep(LGC_FUNCTIONBUTTON_SEQUENCE_STEP_DELAY_MS);
}
}
return true;
}
void Lgc_FunctionButton_RunKeyCombination(
const Lgc_FunctionFeature_Definition& Feature,
quint16 SourceUsage,
QString* p_TextStatus)
{
const QString CombinationText = Feature.SequenceText.trimmed();
if (CombinationText.isEmpty())
{
*p_TextStatus = QStringLiteral("%1 的快捷键尚未配置。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
return;
}
QVector<Lgc_FunctionButton_Struct_SequenceKey> KeyList;
QString ErrorText;
if (!Lgc_FunctionButton_ParseKeyCombinationText(
CombinationText,
SourceUsage,
&KeyList,
&ErrorText))
{
QVector<quint16> UsageList;
if (!Lgc_FunctionButton_ParseLegacySequenceText(
CombinationText,
SourceUsage,
&UsageList,
&ErrorText))
{
*p_TextStatus = QStringLiteral("%1 的快捷键无效:%2")
.arg(Lgc_FunctionButton_GetFeatureName(Feature), ErrorText);
return;
}
KeyList = Lgc_FunctionButton_ConvertUsageListToSequenceKeys(UsageList);
if (KeyList.isEmpty())
{
*p_TextStatus = QStringLiteral("%1 的快捷键无效:存在无法执行的按键。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
return;
}
}
*p_TextStatus = Lgc_FunctionButton_SendKeyCombination(KeyList)
? QStringLiteral("%1 已输出快捷键:%2")
.arg(Lgc_FunctionButton_GetFeatureName(Feature),
Lgc_FunctionButton_FormatKeyCombination(KeyList))
: QStringLiteral("%1 输出快捷键失败。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
}
void Lgc_FunctionButton_RunKeySequence(
const Lgc_FunctionFeature_Definition& Feature,
quint16 SourceUsage,
QString* p_TextStatus)
{
const QString SequenceText = Feature.SequenceText.trimmed();
if (SequenceText.isEmpty())
{
*p_TextStatus = QStringLiteral("%1 的快捷键序列尚未配置。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
return;
}
QVector<QVector<Lgc_FunctionButton_Struct_SequenceKey>> CombinationList;
QString ErrorText;
if (!Lgc_FunctionButton_ParseShortcutSequenceText(
SequenceText,
SourceUsage,
&CombinationList,
&ErrorText))
{
QVector<quint16> UsageList;
if (!Lgc_FunctionButton_ParseLegacySequenceText(
SequenceText,
SourceUsage,
&UsageList,
&ErrorText))
{
*p_TextStatus = QStringLiteral("%1 的快捷键序列无效:%2")
.arg(Lgc_FunctionButton_GetFeatureName(Feature), ErrorText);
return;
}
const QVector<Lgc_FunctionButton_Struct_SequenceKey> KeyList =
Lgc_FunctionButton_ConvertUsageListToSequenceKeys(UsageList);
CombinationList = Lgc_FunctionButton_GroupSequenceKeysIntoCombinations(KeyList);
if (CombinationList.isEmpty())
{
*p_TextStatus = QStringLiteral("%1 的快捷键序列无效:存在无法执行的按键。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
return;
}
}
*p_TextStatus = Lgc_FunctionButton_SendShortcutSequence(CombinationList)
? QStringLiteral("%1 已输出快捷键序列:%2")
.arg(Lgc_FunctionButton_GetFeatureName(Feature),
Lgc_FunctionButton_FormatShortcutSequence(CombinationList))
: QStringLiteral("%1 输出快捷键序列失败。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
}
void Lgc_FunctionButton_RunOpenWebsite(
const Lgc_FunctionFeature_Definition& Feature,
QString* p_TextStatus)
{
const QString UrlText = Feature.WebsiteUrl.trimmed();
const QUrl Url = QUrl::fromUserInput(UrlText);
if (UrlText.isEmpty() || !Url.isValid() || Url.isEmpty())
{
*p_TextStatus = QStringLiteral("%1 的网址配置无效。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
return;
}
*p_TextStatus = QDesktopServices::openUrl(Url)
? QStringLiteral("%1 已打开网址:%2")
.arg(Lgc_FunctionButton_GetFeatureName(Feature), Url.toString())
: QStringLiteral("%1 打开网址失败。")
.arg(Lgc_FunctionButton_GetFeatureName(Feature));
}