first push
This commit is contained in:
127
LOGIC/Lgc_Core.cpp
Normal file
127
LOGIC/Lgc_Core.cpp
Normal 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
65
LOGIC/Lgc_Core.h
Normal 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
320
LOGIC/Lgc_Core_Control.cpp
Normal 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
372
LOGIC/Lgc_Core_Input.cpp
Normal 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
30
LOGIC/Lgc_Core_Private.h
Normal 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
239
LOGIC/Lgc_Func_Button.cpp
Normal 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
62
LOGIC/Lgc_Func_Button.h
Normal 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);
|
||||
573
LOGIC/Lgc_Func_Button_Parse.cpp
Normal file
573
LOGIC/Lgc_Func_Button_Parse.cpp
Normal 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;
|
||||
}
|
||||
76
LOGIC/Lgc_Func_Button_Private.h
Normal file
76
LOGIC/Lgc_Func_Button_Private.h
Normal 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);
|
||||
302
LOGIC/Lgc_Func_Button_Run.cpp
Normal file
302
LOGIC/Lgc_Func_Button_Run.cpp
Normal 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));
|
||||
}
|
||||
Reference in New Issue
Block a user