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

40
APP/APP_GlassCard.cpp Normal file
View File

@@ -0,0 +1,40 @@
#include "APP/APP_GlassCard.h"
#include <QtGui/QPainter>
namespace APP {
APP_GlassCard::APP_GlassCard(QWidget* parent)
: QFrame(parent)
{
// 交给我们自己统一绘制卡片外观,不使用 QFrame 默认边框。
setFrameShape(QFrame::NoFrame);
// 背景由 paintEvent 自绘,这里不走样式表背景。
setAttribute(Qt::WA_StyledBackground, false);
}
void APP_GlassCard::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
/*
* 卡片外观刻意保持简单,方便教学时理解自绘流程:
* 1. 先画一个带圆角的深色底板
* 2. 再画一圈细边框
*/
const QRectF BodyRect = rect().adjusted(1.0, 1.0, -1.0, -1.0);
const qreal Radius = 22.0;
const QColor FillColor(30, 35, 43);
const QColor BorderColor(82, 92, 104);
QPainter Painter(this);
Painter.setRenderHint(QPainter::Antialiasing, true);
// 先画卡片主体。
Painter.setPen(QPen(BorderColor, 1.0));
Painter.setBrush(FillColor);
Painter.drawRoundedRect(BodyRect, Radius, Radius);
}
} // namespace APP

27
APP/APP_GlassCard.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include <QtWidgets/QFrame>
namespace APP {
/*
* 这是项目里所有“卡片容器”的基础控件。
*
* 它只负责统一外观,不负责任何业务逻辑:
* 1. 统一圆角卡片风格
* 2. 统一边框和暗色底板
*
* 上层像主页卡片、调试卡片都直接继承它。
*/
class APP_GlassCard : public QFrame
{
public:
// 构造一个带统一外观的卡片容器。
explicit APP_GlassCard(QWidget* parent = nullptr);
protected:
// 卡片背景和圆角边框都在这里自绘。
void paintEvent(QPaintEvent* event) override;
};
} // namespace APP

171
APP/APP_KeyButton.cpp Normal file
View File

@@ -0,0 +1,171 @@
#include "APP/APP_KeyButton.h"
#include "APP/APP_Theme.h"
#include <QtCore/QtMath>
#include <QtGui/QPainter>
namespace {
QColor App_Func_MixColor(const QColor& Left, const QColor& Right, qreal Value)
{
const qreal Rate = qBound(0.0, Value, 1.0);
return QColor(
qRound(Left.red() + (Right.red() - Left.red()) * Rate),
qRound(Left.green() + (Right.green() - Left.green()) * Rate),
qRound(Left.blue() + (Right.blue() - Left.blue()) * Rate),
qRound(Left.alpha() + (Right.alpha() - Left.alpha()) * Rate));
}
} // namespace
namespace APP {
APP_KeyButton::APP_KeyButton(const APP_KeyInfo& KeyInfo, QWidget* parent)
: QPushButton(parent),
appKeyInfo(KeyInfo)
{
appHintText = appKeyInfo.hint;
setCursor(Qt::PointingHandCursor);
setFlat(true);
setMinimumSize(78, 78);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
}
void APP_KeyButton::App_Func_SetLatched(bool IsLatched)
{
if (appIsLatched == IsLatched)
{
return;
}
appIsLatched = IsLatched;
update();
}
void APP_KeyButton::App_Func_SetPressed(bool IsPressed)
{
if (appIsPressed == IsPressed)
{
return;
}
appIsPressed = IsPressed;
update();
}
void APP_KeyButton::App_Func_SetHintText(const QString& HintText)
{
if (appHintText == HintText)
{
return;
}
appHintText = HintText;
update();
}
void APP_KeyButton::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
const QRectF ButtonRect = rect().adjusted(6.0, 6.0, -6.0, -6.0);
const qreal Radius = 14.0;
QColor FillColor = App_Func_GetBackgroundColor();
QColor OutlineColor = App_Func_GetBorderColor();
if (isDown())
{
FillColor = FillColor.darker(108);
OutlineColor = OutlineColor.darker(112);
}
QPainter Painter(this);
Painter.setRenderHint(QPainter::Antialiasing, true);
Painter.setRenderHint(QPainter::TextAntialiasing, true);
Painter.setPen(QPen(OutlineColor, 1.2));
Painter.setBrush(FillColor);
Painter.drawRoundedRect(ButtonRect, Radius, Radius);
if (!appHintText.isEmpty())
{
Painter.setFont(APP_Theme::App_Func_GetKeyHintFont());
Painter.setPen(App_Func_GetTextColor().lighter(115));
Painter.drawText(
ButtonRect.adjusted(10.0, 8.0, -10.0, -8.0),
Qt::AlignLeft | Qt::AlignTop,
appHintText.toUpper());
}
QFont LabelFont = APP_Theme::App_Func_GetKeyLabelFont();
if (appKeyInfo.label.size() > 2)
{
LabelFont.setPointSize(LabelFont.pointSize() - 4);
}
else if (appKeyInfo.label.size() == 2)
{
LabelFont.setPointSize(LabelFont.pointSize() - 2);
}
Painter.setFont(LabelFont);
Painter.setPen(App_Func_GetTextColor());
Painter.drawText(ButtonRect, Qt::AlignCenter, appKeyInfo.label);
}
QColor APP_KeyButton::App_Func_GetAccentColor() const
{
switch (appKeyInfo.tone)
{
case APP_KeyTone::Aqua:
return QColor(72, 184, 162);
case APP_KeyTone::Amber:
return QColor(224, 172, 76);
case APP_KeyTone::Blue:
return QColor(103, 146, 224);
case APP_KeyTone::Normal:
default:
return QColor(150, 168, 196);
}
}
QColor APP_KeyButton::App_Func_GetBackgroundColor() const
{
const QColor BaseColor(55, 61, 70);
if (appIsPressed)
{
return App_Func_MixColor(BaseColor, App_Func_GetAccentColor(), 0.56);
}
if (appKeyInfo.tone != APP_KeyTone::Normal || appIsLatched)
{
return App_Func_MixColor(BaseColor, App_Func_GetAccentColor(), appIsLatched ? 0.35 : 0.18);
}
return BaseColor;
}
QColor APP_KeyButton::App_Func_GetBorderColor() const
{
const QColor BaseColor(104, 114, 126);
if (appIsPressed)
{
return App_Func_MixColor(BaseColor, App_Func_GetAccentColor(), 0.72);
}
if (appKeyInfo.tone != APP_KeyTone::Normal || appIsLatched)
{
return App_Func_MixColor(BaseColor, App_Func_GetAccentColor(), appIsLatched ? 0.45 : 0.25);
}
return BaseColor;
}
QColor APP_KeyButton::App_Func_GetTextColor() const
{
return QColor(238, 242, 247);
}
} // namespace APP

33
APP/APP_KeyButton.h Normal file
View File

@@ -0,0 +1,33 @@
#pragma once
#include "APP/APP_KeypadModel.h"
#include <QtGui/QColor>
#include <QtWidgets/QPushButton>
namespace APP {
class APP_KeyButton : public QPushButton
{
public:
explicit APP_KeyButton(const APP_KeyInfo& KeyInfo, QWidget* parent = nullptr);
void App_Func_SetLatched(bool IsLatched);
void App_Func_SetPressed(bool IsPressed);
void App_Func_SetHintText(const QString& HintText);
protected:
void paintEvent(QPaintEvent* event) override;
private:
QColor App_Func_GetAccentColor() const;
QColor App_Func_GetBackgroundColor() const;
QColor App_Func_GetBorderColor() const;
QColor App_Func_GetTextColor() const;
APP_KeyInfo appKeyInfo;
QString appHintText;
bool appIsLatched = false;
bool appIsPressed = false;
};
} // namespace APP

119
APP/APP_KeypadModel.cpp Normal file
View File

@@ -0,0 +1,119 @@
#include "APP/APP_KeypadModel.h"
namespace APP {
APP_KeypadModel::APP_KeypadModel()
{
appKeyList = {
{QStringLiteral("num"), QStringLiteral("Num"), QString(), 0x0053, 0, 0, 1, 1, APP_KeyTone::Aqua},
{QStringLiteral("divide"), QStringLiteral("/"), QString(), 0x0054, 0, 1, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("multiply"), QStringLiteral("*"), QString(), 0x0055, 0, 2, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("minus"), QStringLiteral("-"), QString(), 0x0056, 0, 3, 1, 1, APP_KeyTone::Amber},
{QStringLiteral("7"), QStringLiteral("7"), QStringLiteral("Home"), 0x005F, 1, 0, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("8"), QStringLiteral("8"), QStringLiteral("Up"), 0x0060, 1, 1, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("9"), QStringLiteral("9"), QStringLiteral("PgUp"), 0x0061, 1, 2, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("plus"), QStringLiteral("+"), QString(), 0x0057, 1, 3, 2, 1, APP_KeyTone::Aqua},
{QStringLiteral("4"), QStringLiteral("4"), QStringLiteral("Left"), 0x005C, 2, 0, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("5"), QStringLiteral("5"), QString(), 0x005D, 2, 1, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("6"), QStringLiteral("6"), QStringLiteral("Right"), 0x005E, 2, 2, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("1"), QStringLiteral("1"), QStringLiteral("End"), 0x0059, 3, 0, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("2"), QStringLiteral("2"), QStringLiteral("Down"), 0x005A, 3, 1, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("3"), QStringLiteral("3"), QStringLiteral("PgDn"), 0x005B, 3, 2, 1, 1, APP_KeyTone::Normal},
{QStringLiteral("enter"), QStringLiteral("Enter"), QString(), 0x0058, 3, 3, 2, 1, APP_KeyTone::Blue},
{QStringLiteral("0"), QStringLiteral("0"), QStringLiteral("Ins"), 0x0062, 4, 0, 1, 2, APP_KeyTone::Normal},
{QStringLiteral("dot"), QStringLiteral("."), QStringLiteral("Del"), 0x0063, 4, 2, 1, 1, APP_KeyTone::Normal}
};
}
const QVector<APP_KeyInfo>& APP_KeypadModel::App_Func_GetKeyList() const
{
return appKeyList;
}
bool APP_KeypadModel::App_Func_IsLatched(const QString& KeyId) const
{
return (KeyId == QStringLiteral("num")) && appNumLockOn;
}
bool APP_KeypadModel::App_Func_IsPressed(const QString& KeyId) const
{
return appPressedKeyIdList.contains(KeyId);
}
quint16 APP_KeypadModel::App_Func_GetUsageFromKeyId(const QString& KeyId) const
{
for (const APP_KeyInfo& KeyInfo : appKeyList)
{
if (KeyInfo.id == KeyId)
{
return KeyInfo.usage;
}
}
return 0;
}
QString APP_KeypadModel::App_Func_GetKeyIdFromUsage(quint16 Usage) const
{
for (const APP_KeyInfo& KeyInfo : appKeyList)
{
if (KeyInfo.usage == Usage)
{
return KeyInfo.id;
}
}
return QString();
}
QString APP_KeypadModel::App_Func_GetLabelFromUsage(quint16 Usage) const
{
for (const APP_KeyInfo& KeyInfo : appKeyList)
{
if (KeyInfo.usage == Usage)
{
return KeyInfo.label;
}
}
return QString();
}
QString APP_KeypadModel::App_Func_GetDefaultHint(const QString& KeyId) const
{
for (const APP_KeyInfo& KeyInfo : appKeyList)
{
if (KeyInfo.id == KeyId)
{
return KeyInfo.hint;
}
}
return QString();
}
void APP_KeypadModel::App_Func_SetNumLockOn(bool IsOn)
{
appNumLockOn = IsOn;
}
void APP_KeypadModel::App_Func_ClearPressedKeys()
{
appPressedKeyIdList.clear();
}
void APP_KeypadModel::App_Func_SetPressedKeysFromUsageList(const QVector<quint16>& UsageList)
{
appPressedKeyIdList.clear();
for (quint16 Usage : UsageList)
{
const QString KeyId = App_Func_GetKeyIdFromUsage(Usage);
if (!KeyId.isEmpty() && !appPressedKeyIdList.contains(KeyId))
{
appPressedKeyIdList.append(KeyId);
}
}
}
} // namespace APP

52
APP/APP_KeypadModel.h Normal file
View File

@@ -0,0 +1,52 @@
#pragma once
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVector>
namespace APP {
enum class APP_KeyTone
{
Normal,
Aqua,
Amber,
Blue
};
struct APP_KeyInfo
{
QString id;
QString label;
QString hint;
quint16 usage = 0;
int row = 0;
int column = 0;
int rowSpan = 1;
int columnSpan = 1;
APP_KeyTone tone = APP_KeyTone::Normal;
};
class APP_KeypadModel
{
public:
APP_KeypadModel();
const QVector<APP_KeyInfo>& App_Func_GetKeyList() const;
bool App_Func_IsLatched(const QString& KeyId) const;
bool App_Func_IsPressed(const QString& KeyId) const;
quint16 App_Func_GetUsageFromKeyId(const QString& KeyId) const;
QString App_Func_GetKeyIdFromUsage(quint16 Usage) const;
QString App_Func_GetLabelFromUsage(quint16 Usage) const;
QString App_Func_GetDefaultHint(const QString& KeyId) const;
void App_Func_SetNumLockOn(bool IsOn);
void App_Func_ClearPressedKeys();
void App_Func_SetPressedKeysFromUsageList(const QVector<quint16>& UsageList);
private:
QVector<APP_KeyInfo> appKeyList;
QStringList appPressedKeyIdList;
bool appNumLockOn = false;
};
} // namespace APP

131
APP/APP_Theme.cpp Normal file
View File

@@ -0,0 +1,131 @@
#include "APP/APP_Theme.h"
#include <QtGui/QFontDatabase>
#include <QtWidgets/QApplication>
namespace APP {
QPalette APP_Theme::App_Func_GetPalette()
{
/*
* 不用样式表时Qt 最稳妥的统一美化方式就是调色板:
* 1. 先选 Fusion 风格
* 2. 再给标准控件一组统一颜色
*/
QPalette Palette;
const QColor WindowColor(20, 25, 33);
const QColor BaseColor(28, 34, 42);
const QColor AltBaseColor(34, 40, 49);
const QColor ButtonColor(38, 44, 54);
const QColor BorderHintColor(86, 96, 108);
const QColor HighlightColor(72, 184, 162);
const QColor TextColor(238, 242, 247);
const QColor DimTextColor(162, 170, 182);
Palette.setColor(QPalette::Window, WindowColor);
Palette.setColor(QPalette::WindowText, TextColor);
Palette.setColor(QPalette::Base, BaseColor);
Palette.setColor(QPalette::AlternateBase, AltBaseColor);
Palette.setColor(QPalette::Text, TextColor);
Palette.setColor(QPalette::Button, ButtonColor);
Palette.setColor(QPalette::ButtonText, TextColor);
Palette.setColor(QPalette::BrightText, QColor(255, 255, 255));
Palette.setColor(QPalette::Light, BorderHintColor.lighter(120));
Palette.setColor(QPalette::Midlight, BorderHintColor);
Palette.setColor(QPalette::Mid, BorderHintColor.darker(120));
Palette.setColor(QPalette::Dark, WindowColor.darker(140));
Palette.setColor(QPalette::Shadow, QColor(0, 0, 0, 140));
Palette.setColor(QPalette::Highlight, HighlightColor);
Palette.setColor(QPalette::HighlightedText, TextColor);
Palette.setColor(QPalette::ToolTipBase, BaseColor);
Palette.setColor(QPalette::ToolTipText, TextColor);
Palette.setColor(QPalette::Link, QColor(103, 146, 224));
Palette.setColor(QPalette::PlaceholderText, QColor(170, 178, 188, 170));
Palette.setColor(QPalette::Disabled, QPalette::WindowText, DimTextColor);
Palette.setColor(QPalette::Disabled, QPalette::Text, DimTextColor);
Palette.setColor(QPalette::Disabled, QPalette::ButtonText, DimTextColor);
return Palette;
}
QFont APP_Theme::App_Func_GetBodyFont()
{
// 正文用相对稳妥、系统常见的字体候选。
QFont Font(App_Func_PickFontFamily(QStringList()
<< QStringLiteral("Segoe UI Variable Text")
<< QStringLiteral("Microsoft YaHei UI")
<< QStringLiteral("Segoe UI")
<< QStringLiteral("Bahnschrift")));
Font.setPointSize(10);
Font.setWeight(QFont::Medium);
return Font;
}
QFont APP_Theme::App_Func_GetTitleFont()
{
// 页面标题字号更大、字重更高。
QFont Font(App_Func_PickFontFamily(QStringList()
<< QStringLiteral("Segoe UI Variable Display Semibold")
<< QStringLiteral("Microsoft YaHei UI")
<< QStringLiteral("Bahnschrift SemiBold")));
Font.setPointSize(21);
Font.setWeight(QFont::DemiBold);
return Font;
}
QFont APP_Theme::App_Func_GetMetricFont()
{
// 指标类标题用比正文更有力度的字重。
QFont Font(App_Func_PickFontFamily(QStringList()
<< QStringLiteral("Bahnschrift SemiBold")
<< QStringLiteral("Segoe UI Semibold")
<< QStringLiteral("Microsoft YaHei UI")));
Font.setPointSize(12);
Font.setWeight(QFont::DemiBold);
return Font;
}
QFont APP_Theme::App_Func_GetKeyLabelFont()
{
// 按键主文字字号较大,保证小键盘一眼能看清。
QFont Font(App_Func_PickFontFamily(QStringList()
<< QStringLiteral("Bahnschrift SemiBold")
<< QStringLiteral("Segoe UI Semibold")
<< QStringLiteral("Microsoft YaHei UI")));
Font.setPointSize(22);
return Font;
}
QFont APP_Theme::App_Func_GetKeyHintFont()
{
// 按键 hint 放左上角,所以字号更小。
QFont Font(App_Func_PickFontFamily(QStringList()
<< QStringLiteral("Segoe UI Semibold")
<< QStringLiteral("Bahnschrift SemiBold")
<< QStringLiteral("Microsoft YaHei UI")));
Font.setPointSize(8);
Font.setLetterSpacing(QFont::AbsoluteSpacing, 1.0);
return Font;
}
QString APP_Theme::App_Func_PickFontFamily(const QStringList& FamilyList)
{
// 从候选字体里依次挑选系统真实存在的字体。
const QFontDatabase Database;
const QStringList AvailableFamilyList = Database.families();
for (int Index = 0; Index < FamilyList.size(); ++Index)
{
const QString& Family = FamilyList.at(Index);
if (AvailableFamilyList.contains(Family))
{
return Family;
}
}
// 如果都不存在,就退回 Qt 当前默认字体。
return QApplication::font().family();
}
} // namespace APP

38
APP/APP_Theme.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include <QtCore/QStringList>
#include <QtGui/QFont>
#include <QtGui/QPalette>
namespace APP {
/*
* 主题模块现在只保留一套固定暗色风格。
*
* - 不参与 DRI 枚举
* - 不参与协议解析
* - 不参与业务判断
*/
class APP_Theme
{
public:
// 返回标准控件使用的统一调色板。
static QPalette App_Func_GetPalette();
// 正文说明文字的默认字体。
static QFont App_Func_GetBodyFont();
// 页面标题字体。
static QFont App_Func_GetTitleFont();
// 指标、卡片主标题使用的强调字体。
static QFont App_Func_GetMetricFont();
// 键帽中央主文字字体。
static QFont App_Func_GetKeyLabelFont();
// 键帽角落提示文字字体。
static QFont App_Func_GetKeyHintFont();
private:
// 从候选字体列表中挑出当前系统真实存在的一项。
static QString App_Func_PickFontFamily(const QStringList& FamilyList);
};
} // namespace APP

420
APP/APP_UIWindow.cpp Normal file
View File

@@ -0,0 +1,420 @@
#include "APP/APP_UIWindow.h"
#include "APP/APP_GlassCard.h"
#include "APP/APP_KeyButton.h"
#include "APP/APP_Theme.h"
#include "APP/APP_UIWindow_Private.h"
#include "LOGIC/Lgc_Func_Button.h"
#include <QtCore/QSignalBlocker>
#include <QtGui/QPainter>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QFormLayout>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QSizePolicy>
#include <QtWidgets/QStackedWidget>
#include <QtWidgets/QTabWidget>
#include <QtWidgets/QTableWidget>
#include <QtWidgets/QTableWidgetItem>
#include <QtWidgets/QVBoxLayout>
namespace APP {
namespace
{
QLabel* App_Func_CreateLabel(
QWidget* parent,
const QString& Text,
const QFont& Font,
bool WordWrap = false)
{
QLabel* p_Label = new QLabel(Text, parent);
p_Label->setFont(Font);
p_Label->setAttribute(Qt::WA_TranslucentBackground, true);
p_Label->setWordWrap(WordWrap);
return p_Label;
}
APP_GlassCard* App_Func_CreateCard(QWidget* parent, QVBoxLayout** pp_Layout)
{
APP_GlassCard* p_Card = new APP_GlassCard(parent);
QVBoxLayout* p_Layout = new QVBoxLayout(p_Card);
p_Layout->setContentsMargins(20, 20, 20, 20);
p_Layout->setSpacing(14);
*pp_Layout = p_Layout;
return p_Card;
}
void App_Func_SetGridStretch(QGridLayout* p_Grid, int ColumnCount, int RowCount)
{
for (int Column = 0; Column < ColumnCount; ++Column)
{
p_Grid->setColumnStretch(Column, 1);
}
for (int Row = 0; Row < RowCount; ++Row)
{
p_Grid->setRowStretch(Row, 1);
}
}
} // namespace
int App_Func_GetFeatureStackIndex(Lgc_FunctionFeature_Type Type)
{
switch (Type)
{
case Lgc_FunctionFeature_Type::KeyCombination:
case Lgc_FunctionFeature_Type::KeySequence:
return 0;
case Lgc_FunctionFeature_Type::Website:
return 1;
default:
return 0;
}
}
bool App_Func_IsKeyRecordFeatureType(Lgc_FunctionFeature_Type Type)
{
return (Type == Lgc_FunctionFeature_Type::KeyCombination) ||
(Type == Lgc_FunctionFeature_Type::KeySequence);
}
QString App_Func_GetWebsiteEditText(const QString& UrlText)
{
const QString DisplayText = UrlText.trimmed();
return DisplayText.isEmpty() ? QStringLiteral("https://") : DisplayText;
}
App_UIWindow::App_UIWindow(QWidget* parent)
: QWidget(parent)
{
App_Func_InitWindow();
App_Func_InitUi();
App_Func_InitConnect();
App_Func_InitLogic();
App_Func_RefreshUi();
}
App_UIWindow::~App_UIWindow()
{
Lgc_Core_Close(&appLgcState);
}
void App_UIWindow::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event);
QPainter Painter(this);
Painter.setRenderHint(QPainter::Antialiasing, true);
Painter.fillRect(rect(), palette().color(QPalette::Window));
}
void App_UIWindow::resizeEvent(QResizeEvent* event)
{
QWidget::resizeEvent(event);
App_Func_UpdateFeatureEditorHeight();
}
bool App_UIWindow::nativeEvent(const QByteArray& EventType, void* p_Message, long* p_Result)
{
Q_UNUSED(EventType);
App_Func_HandleSequenceRecordMessage(p_Message);
Lgc_Core_HandleNativeMessage(&appLgcState, p_Message);
return QWidget::nativeEvent(EventType, p_Message, p_Result);
}
void App_UIWindow::App_Func_InitWindow()
{
setWindowTitle(QStringLiteral("数字键盘上位机"));
#if APP_ENABLE_DEBUG_WINDOW
setMinimumSize(820, 960);
resize(900, 1040);
#else
setMinimumSize(760, 820);
resize(820, 900);
#endif
setAttribute(Qt::WA_StyledBackground, true);
}
void App_UIWindow::App_Func_InitUi()
{
QVBoxLayout* p_RootLayout = new QVBoxLayout(this);
p_RootLayout->setContentsMargins(26, 22, 26, 24);
p_RootLayout->setSpacing(14);
appPageTab = new QTabWidget(this);
appPageTab->setDocumentMode(true);
appPageTab->setMovable(false);
appPageTab->addTab(App_Func_CreatePadCard(), QStringLiteral("按键映射"));
appFeaturePageIndex = appPageTab->addTab(App_Func_CreateFunctionConfigCard(), QStringLiteral("功能表"));
#if APP_ENABLE_DEBUG_WINDOW
appPageTab->addTab(App_Func_CreateDebugCard(), QStringLiteral("调试"));
#endif
p_RootLayout->addWidget(appPageTab, 1);
}
void App_UIWindow::App_Func_InitConnect()
{
connect(&appTimerPoll, &QTimer::timeout, this, &App_UIWindow::App_Func_OnPollTimer);
connect(&appTimerAutoRefreshDevice, &QTimer::timeout, this, [this]()
{
if (appLgcState.IsConnected)
{
return;
}
const QString OldTextLog = appLgcState.TextLog;
Lgc_Core_RefreshDevice(&appLgcState);
if (!appLgcState.IsConnected)
{
appLgcState.TextLog = OldTextLog;
}
App_Func_RefreshAfterLogicChange();
});
connect(appFeatureAddButton, &QPushButton::clicked, this, &App_UIWindow::App_Func_AddFeature);
connect(appFeatureDeleteButton, &QPushButton::clicked, this, &App_UIWindow::App_Func_DeleteFeature);
connect(appFeatureTable, &QTableWidget::itemSelectionChanged, this, [this]()
{
const QModelIndexList IndexList = appFeatureTable->selectionModel()->selectedRows();
if (IndexList.isEmpty())
{
App_Func_SelectFeature(0);
return;
}
const int Row = IndexList.first().row();
const QTableWidgetItem* p_Item = appFeatureTable->item(Row, 0);
App_Func_SelectFeature(p_Item == nullptr ? 0 : p_Item->data(Qt::UserRole).toInt());
});
const auto ConnectSaveSignal = [this](auto Sender, auto Signal)
{
connect(Sender, Signal, this, [this]()
{
if (!appIsUpdatingFeatureUi)
{
App_Func_SaveFeatureFromUi();
}
});
};
ConnectSaveSignal(appFeatureNameEdit, &QLineEdit::textChanged);
ConnectSaveSignal(appFeatureDescriptionEdit, &QLineEdit::textChanged);
ConnectSaveSignal(appFeatureTypeCombo, qOverload<int>(&QComboBox::currentIndexChanged));
ConnectSaveSignal(appFeatureSequenceEdit, &QLineEdit::textChanged);
ConnectSaveSignal(appFeatureWebsiteEdit, &QLineEdit::textChanged);
connect(appFeatureSequenceRecordStartButton, &QPushButton::clicked, this, &App_UIWindow::App_Func_StartSequenceRecording);
connect(appFeatureSequenceRecordStopButton, &QPushButton::clicked, this, &App_UIWindow::App_Func_StopSequenceRecording);
#if APP_ENABLE_DEBUG_WINDOW
connect(appDebugPanel->Debug_Func_GetRefreshButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnRefreshDeviceClicked);
connect(appDebugPanel->Debug_Func_GetClearButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnClearLogClicked);
connect(appDebugPanel->Debug_Func_GetApplyConfigButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnApplyDeviceConfigClicked);
connect(appDebugPanel->Debug_Func_GetSyncTimeButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnSyncTimeClicked);
connect(appDebugPanel->Debug_Func_GetModeSwitchButton(), &QPushButton::clicked, this, &App_UIWindow::App_Func_OnModeSwitchClicked);
#endif
}
void App_UIWindow::App_Func_InitLogic()
{
Lgc_Core_Init(&appLgcState);
Lgc_Core_SetWindowHandle(&appLgcState, reinterpret_cast<void*>(winId()));
App_Func_RefreshFeatureTable();
#if APP_ENABLE_DEBUG_WINDOW
App_Func_RefreshDeviceConfigFromState();
#endif
Lgc_Core_Start(&appLgcState);
appTimerPoll.setInterval(30);
appTimerPoll.start();
appTimerAutoRefreshDevice.setInterval(1500);
appTimerAutoRefreshDevice.start();
App_Func_RefreshAfterLogicChange();
}
QWidget* App_UIWindow::App_Func_CreatePadCard()
{
QVBoxLayout* p_Layout = nullptr;
APP_GlassCard* p_Card = App_Func_CreateCard(this, &p_Layout);
p_Layout->addWidget(App_Func_CreateLabel(
p_Card,
QStringLiteral("按键映射"),
APP_Theme::App_Func_GetMetricFont()));
p_Layout->addWidget(App_Func_CreateLabel(
p_Card,
QStringLiteral("左键直接模拟真实小键盘按下/抬起;右键把当前按键绑定到某个功能。绑定后,键帽左上角会显示功能名,悬停会显示功能简介。"),
APP_Theme::App_Func_GetBodyFont(),
true));
QGridLayout* p_Grid = new QGridLayout();
p_Grid->setSpacing(14);
for (const APP_KeyInfo& Key : appKeypadModel.App_Func_GetKeyList())
{
APP_KeyButton* p_Button = new APP_KeyButton(Key, p_Card);
p_Button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(p_Button, &QPushButton::pressed, this, [this, Key]() { App_Func_HandleUiKeyPressed(Key.usage); });
connect(p_Button, &QPushButton::released, this, [this, Key]() { App_Func_HandleUiKeyReleased(Key.usage); });
connect(p_Button, &QWidget::customContextMenuRequested, this, [this, p_Button, Key](const QPoint&)
{
App_Func_ShowKeyMenu(
Key.usage,
p_Button->mapToGlobal(QPoint(p_Button->width() / 2, p_Button->height() / 2)));
});
appKeypadButtonMap.insert(Key.id, p_Button);
p_Grid->addWidget(p_Button, Key.row, Key.column, Key.rowSpan, Key.columnSpan);
}
App_Func_SetGridStretch(p_Grid, 4, 5);
p_Layout->addLayout(p_Grid, 1);
return p_Card;
}
QWidget* App_UIWindow::App_Func_CreateFunctionConfigCard()
{
QVBoxLayout* p_Layout = nullptr;
APP_GlassCard* p_Card = App_Func_CreateCard(this, &p_Layout);
const auto AddRow = [p_Card](QFormLayout* p_Form, const QString& LabelText, QWidget* p_Field)
{
p_Form->addRow(App_Func_CreateLabel(p_Card, LabelText, APP_Theme::App_Func_GetBodyFont()), p_Field);
};
p_Layout->addWidget(App_Func_CreateLabel(
p_Card,
QStringLiteral("功能表"),
APP_Theme::App_Func_GetMetricFont()));
p_Layout->addWidget(App_Func_CreateLabel(
p_Card,
QStringLiteral("功能表默认为空,请先添加功能,再把按钮绑定到某个功能。当前支持“快捷键”“快捷键序列”和“打开网址”三种功能类型。"),
APP_Theme::App_Func_GetBodyFont(),
true));
QHBoxLayout* p_TopRow = new QHBoxLayout();
p_TopRow->setContentsMargins(0, 0, 0, 0);
p_TopRow->setSpacing(10);
appFeatureAddButton = new QPushButton(QStringLiteral("添加功能"), p_Card);
appFeatureDeleteButton = new QPushButton(QStringLiteral("删除功能"), p_Card);
appFeatureDeleteButton->setEnabled(false);
p_TopRow->addWidget(appFeatureAddButton);
p_TopRow->addWidget(appFeatureDeleteButton);
p_TopRow->addStretch(1);
p_Layout->addLayout(p_TopRow);
appFeatureTable = new QTableWidget(p_Card);
appFeatureTable->setColumnCount(3);
appFeatureTable->setHorizontalHeaderLabels({ QStringLiteral("功能名"), QStringLiteral("功能简介"), QStringLiteral("类型") });
appFeatureTable->setSelectionBehavior(QAbstractItemView::SelectRows);
appFeatureTable->setSelectionMode(QAbstractItemView::SingleSelection);
appFeatureTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
appFeatureTable->setAlternatingRowColors(true);
appFeatureTable->verticalHeader()->setVisible(false);
appFeatureTable->horizontalHeader()->setStretchLastSection(false);
appFeatureTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
appFeatureTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
appFeatureTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
appFeatureTable->setMinimumHeight(220);
p_Layout->addWidget(appFeatureTable);
QFormLayout* p_Form = new QFormLayout();
p_Form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
p_Form->setLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
p_Form->setHorizontalSpacing(10);
p_Form->setVerticalSpacing(10);
appFeatureNameEdit = new QLineEdit(p_Card);
appFeatureNameEdit->setPlaceholderText(QStringLiteral("例如功能1 / 打开4399 / 前缀补码"));
AddRow(p_Form, QStringLiteral("功能名"), appFeatureNameEdit);
appFeatureDescriptionEdit = new QLineEdit(p_Card);
appFeatureDescriptionEdit->setPlaceholderText(QStringLiteral("例如:打开 4399 首页"));
AddRow(p_Form, QStringLiteral("功能简介"), appFeatureDescriptionEdit);
appFeatureTypeCombo = new QComboBox(p_Card);
appFeatureTypeCombo->addItem(
Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type::KeyCombination),
static_cast<int>(Lgc_FunctionFeature_Type::KeyCombination));
appFeatureTypeCombo->addItem(
Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type::KeySequence),
static_cast<int>(Lgc_FunctionFeature_Type::KeySequence));
appFeatureTypeCombo->addItem(
Lgc_FunctionButton_GetFeatureTypeText(Lgc_FunctionFeature_Type::Website),
static_cast<int>(Lgc_FunctionFeature_Type::Website));
AddRow(p_Form, QStringLiteral("功能类型"), appFeatureTypeCombo);
appFeatureEditorStack = new QStackedWidget(p_Card);
appFeatureEditorStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QWidget* p_SequencePage = new QWidget(appFeatureEditorStack);
QFormLayout* p_SequenceForm = new QFormLayout(p_SequencePage);
p_SequenceForm->setContentsMargins(0, 0, 0, 0);
p_SequenceForm->setHorizontalSpacing(10);
p_SequenceForm->setVerticalSpacing(10);
QWidget* p_SequenceEditor = new QWidget(p_SequencePage);
QHBoxLayout* p_SequenceEditorLayout = new QHBoxLayout(p_SequenceEditor);
p_SequenceEditorLayout->setContentsMargins(0, 0, 0, 0);
p_SequenceEditorLayout->setSpacing(8);
appFeatureSequenceEdit = new QLineEdit(p_SequenceEditor);
appFeatureSequenceEdit->setPlaceholderText(QStringLiteral("例如Ctrl+C"));
appFeatureSequenceRecordStartButton = new QPushButton(QStringLiteral("开始录入"), p_SequenceEditor);
appFeatureSequenceRecordStopButton = new QPushButton(QStringLiteral("退出录入"), p_SequenceEditor);
appFeatureSequenceRecordStopButton->setEnabled(false);
p_SequenceEditorLayout->addWidget(appFeatureSequenceEdit, 1);
p_SequenceEditorLayout->addWidget(appFeatureSequenceRecordStartButton);
p_SequenceEditorLayout->addWidget(appFeatureSequenceRecordStopButton);
p_SequenceForm->addRow(QStringLiteral("快捷键"), p_SequenceEditor);
QWidget* p_WebsitePage = new QWidget(appFeatureEditorStack);
QVBoxLayout* p_WebsiteLayout = new QVBoxLayout(p_WebsitePage);
p_WebsiteLayout->setContentsMargins(0, 0, 0, 0);
p_WebsiteLayout->setSpacing(0);
appFeatureWebsiteEdit = new QLineEdit(p_WebsitePage);
appFeatureWebsiteEdit->setPlaceholderText(QStringLiteral("例如直接输入 4399.com 或 www.4399.com"));
p_WebsiteLayout->addWidget(appFeatureWebsiteEdit);
appFeatureEditorStack->addWidget(p_SequencePage);
appFeatureEditorStack->addWidget(p_WebsitePage);
AddRow(p_Form, QStringLiteral("功能参数"), appFeatureEditorStack);
appFeatureBindingSummaryLabel = App_Func_CreateLabel(
p_Card,
QStringLiteral("当前还没有功能,请点击“添加功能”。"),
APP_Theme::App_Func_GetBodyFont(),
true);
AddRow(p_Form, QStringLiteral("绑定情况"), appFeatureBindingSummaryLabel);
appFunctionLabelStatus = App_Func_CreateLabel(
p_Card,
QStringLiteral("等待按键动作。"),
APP_Theme::App_Func_GetBodyFont(),
true);
AddRow(p_Form, QStringLiteral("最近一次动作"), appFunctionLabelStatus);
p_Layout->addLayout(p_Form);
p_Layout->addStretch(1);
return p_Card;
}
#if APP_ENABLE_DEBUG_WINDOW
QWidget* App_UIWindow::App_Func_CreateDebugCard()
{
appDebugPanel = new DEBUG::Debug_Panel(this);
appDebugPanel->Debug_Func_SetConnectionText(QStringLiteral("未连接,等待枚举设备。"), false);
appDebugPanel->Debug_Func_SetLogText(QStringLiteral("等待收到输入包。"));
return appDebugPanel;
}
#endif
} // namespace APP

125
APP/APP_UIWindow.h Normal file
View File

@@ -0,0 +1,125 @@
#pragma once
#include "APP/APP_KeypadModel.h"
#include "DEBUG/Debug_Config.h"
#include "LOGIC/Lgc_Core.h"
#include <QtCore/QHash>
#include <QtCore/QSet>
#include <QtCore/QTimer>
#include <QtWidgets/QWidget>
#if APP_ENABLE_DEBUG_WINDOW
#include "DEBUG/Debug_Panel.h"
#endif
class QLabel;
class QComboBox;
class QLineEdit;
class QPushButton;
class QResizeEvent;
class QStackedWidget;
class QTabWidget;
class QTableWidget;
namespace APP {
class APP_KeyButton;
class App_UIWindow : public QWidget
{
public:
explicit App_UIWindow(QWidget* parent = nullptr);
~App_UIWindow() override;
protected:
void paintEvent(QPaintEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
bool nativeEvent(const QByteArray& EventType, void* p_Message, long* p_Result) override;
private:
void App_Func_InitWindow();
void App_Func_InitUi();
void App_Func_InitConnect();
void App_Func_InitLogic();
void App_Func_RefreshUi();
void App_Func_RefreshKeypadState();
void App_Func_RefreshKeypadButtons();
void App_Func_RefreshFeatureTable();
void App_Func_RefreshFunctionStatus();
void App_Func_RefreshDebugView();
void App_Func_RefreshAfterLogicChange();
void App_Func_SelectFeature(int FeatureId, bool SwitchToFeaturePage = false);
void App_Func_SaveFeatureFromUi();
void App_Func_UpdateFeatureEditorState();
void App_Func_UpdateFeatureEditorHeight();
void App_Func_AddFeature();
void App_Func_DeleteFeature();
void App_Func_AssignFeatureToUsage(quint16 Usage, int FeatureId);
void App_Func_HandleUiKeyPressed(quint16 Usage);
void App_Func_HandleUiKeyReleased(quint16 Usage);
void App_Func_ShowKeyMenu(quint16 Usage, const QPoint& GlobalPos);
void App_Func_StartSequenceRecording();
void App_Func_StopSequenceRecording();
void App_Func_UpdateSequenceRecordingUi();
bool App_Func_HandleSequenceRecordMessage(void* p_Message);
void App_Func_AppendRecordedSequenceToken(const QString& Token);
QString App_Func_GetKeyHintText(const QString& KeyId) const;
QString App_Func_GetFeatureNameById(int FeatureId) const;
QString App_Func_GetFeatureDescriptionById(int FeatureId) const;
QString App_Func_GetFeatureDescriptionForUsage(quint16 Usage) const;
QString App_Func_GetDefaultKeyDescription(quint16 Usage) const;
QString App_Func_GetFeatureBindingSummary(int FeatureId) const;
void App_Func_OnPollTimer();
#if APP_ENABLE_DEBUG_WINDOW
void App_Func_OnApplyDeviceConfigClicked();
void App_Func_OnRefreshDeviceClicked();
void App_Func_OnClearLogClicked();
void App_Func_OnSyncTimeClicked();
void App_Func_OnModeSwitchClicked();
void App_Func_RefreshDeviceConfigFromState();
#endif
QWidget* App_Func_CreatePadCard();
QWidget* App_Func_CreateFunctionConfigCard();
#if APP_ENABLE_DEBUG_WINDOW
QWidget* App_Func_CreateDebugCard();
#endif
APP_KeypadModel appKeypadModel;
QHash<QString, APP_KeyButton*> appKeypadButtonMap;
QTabWidget* appPageTab = nullptr;
int appFeaturePageIndex = 0;
QLabel* appFunctionLabelStatus = nullptr;
QTableWidget* appFeatureTable = nullptr;
QPushButton* appFeatureAddButton = nullptr;
QPushButton* appFeatureDeleteButton = nullptr;
QLabel* appFeatureParameterHintLabel = nullptr;
QLabel* appFeatureBindingSummaryLabel = nullptr;
QLineEdit* appFeatureNameEdit = nullptr;
QLineEdit* appFeatureDescriptionEdit = nullptr;
QComboBox* appFeatureTypeCombo = nullptr;
QStackedWidget* appFeatureEditorStack = nullptr;
QLineEdit* appFeatureSequenceEdit = nullptr;
QLineEdit* appFeatureWebsiteEdit = nullptr;
QPushButton* appFeatureSequenceRecordStartButton = nullptr;
QPushButton* appFeatureSequenceRecordStopButton = nullptr;
bool appIsUpdatingFeatureUi = false;
bool appIsSequenceRecording = false;
int appSelectedFeatureId = 0;
QSet<quint16> appUiPressedUsageSet;
QSet<QString> appSequenceRecordingPressedKeySet;
#if APP_ENABLE_DEBUG_WINDOW
DEBUG::Debug_Panel* appDebugPanel = nullptr;
#endif
QTimer appTimerPoll;
QTimer appTimerAutoRefreshDevice;
Lgc_Core_Struct_State appLgcState;
};
} // namespace APP

View File

@@ -0,0 +1,519 @@
#include "APP/APP_UIWindow.h"
#include "APP/APP_KeyButton.h"
#include "APP/APP_UIWindow_Private.h"
#include "DEBUG/Debug_Panel.h"
#include <QtCore/QSignalBlocker>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLayout>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStackedWidget>
#include <QtWidgets/QTableWidget>
#include <QtWidgets/QTableWidgetItem>
namespace APP {
namespace
{
bool App_Func_HasDebugSendRoute(const Lgc_Core_Struct_State& State)
{
return State.DriVendorPort.ReadPort.IsOpened || State.DriBlePort.IsConnected;
}
QString App_Func_GetDebugSendModeText(const Lgc_Core_Struct_State& State)
{
if (State.DriBlePort.IsConnected || State.DriVendorPort.IsBluetoothTransport)
{
return QStringLiteral("蓝牙模式");
}
if (State.DriVendorPort.ReadPort.IsOpened)
{
return QStringLiteral("USB 模式");
}
return QStringLiteral("未连接");
}
QString App_Func_GetDebugConfigStatusText(const Lgc_Core_Struct_State& State)
{
return QStringLiteral("目标 USB 0x%1:0x%2 / 当前发包模式:%3")
.arg(State.DeviceConfig.VendorId, 4, 16, QLatin1Char('0'))
.arg(State.DeviceConfig.ProductId, 4, 16, QLatin1Char('0'))
.arg(App_Func_GetDebugSendModeText(State))
.toUpper();
}
} // namespace
void App_UIWindow::App_Func_RefreshUi()
{
App_Func_RefreshKeypadButtons();
App_Func_RefreshFunctionStatus();
update();
}
void App_UIWindow::App_Func_RefreshKeypadState()
{
appKeypadModel.App_Func_SetNumLockOn(appLgcState.IsSystemNumLockOn);
const QVector<quint16>* p_UsageList = appLgcState.IsPhysicalKeyStateValid
? &appLgcState.PhysicalUsageList
: (appLgcState.IsVisibleKeyStateValid ? &appLgcState.VisibleUsageList : nullptr);
if (p_UsageList != nullptr)
{
appKeypadModel.App_Func_SetPressedKeysFromUsageList(*p_UsageList);
}
else
{
appKeypadModel.App_Func_ClearPressedKeys();
}
}
void App_UIWindow::App_Func_RefreshKeypadButtons()
{
for (auto It = appKeypadButtonMap.begin(); It != appKeypadButtonMap.end(); ++It)
{
const QString KeyId = It.key();
const quint16 Usage = appKeypadModel.App_Func_GetUsageFromKeyId(KeyId);
const bool HasFeature =
Lgc_FunctionButton_HasUsageFeature(appLgcState.FunctionButtonConfig, Usage);
APP_KeyButton* p_Button = It.value();
p_Button->App_Func_SetLatched(appKeypadModel.App_Func_IsLatched(KeyId) || HasFeature);
p_Button->App_Func_SetPressed(appKeypadModel.App_Func_IsPressed(KeyId));
p_Button->App_Func_SetHintText(App_Func_GetKeyHintText(KeyId));
p_Button->setToolTip(App_Func_GetFeatureDescriptionForUsage(Usage));
}
}
void App_UIWindow::App_Func_RefreshFeatureTable()
{
if (appFeatureTable == nullptr)
{
return;
}
const QVector<int> FeatureIdList = Lgc_FunctionButton_GetFeatureIdList(appLgcState.FunctionButtonConfig);
QSignalBlocker Blocker(appFeatureTable);
appFeatureTable->clearContents();
appFeatureTable->setRowCount(FeatureIdList.size());
int TargetRow = -1;
for (int Row = 0; Row < FeatureIdList.size(); ++Row)
{
const int FeatureId = FeatureIdList.at(Row);
const Lgc_FunctionFeature_Definition Feature = Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, FeatureId);
QTableWidgetItem* p_NameItem = new QTableWidgetItem(Lgc_FunctionButton_GetFeatureName(Feature));
p_NameItem->setData(Qt::UserRole, FeatureId);
appFeatureTable->setItem(Row, 0, p_NameItem);
appFeatureTable->setItem(Row, 1, new QTableWidgetItem(App_Func_GetFeatureDescriptionById(FeatureId)));
appFeatureTable->setItem(Row, 2, new QTableWidgetItem(Lgc_FunctionButton_GetFeatureTypeText(Feature.Type)));
if (FeatureId == appSelectedFeatureId)
{
TargetRow = Row;
}
}
appSelectedFeatureId =
TargetRow >= 0 ? appSelectedFeatureId : (FeatureIdList.isEmpty() ? 0 : FeatureIdList.first());
TargetRow = TargetRow >= 0 ? TargetRow : (FeatureIdList.isEmpty() ? -1 : 0);
if (TargetRow >= 0)
{
appFeatureTable->selectRow(TargetRow);
}
else
{
appFeatureTable->clearSelection();
}
App_Func_UpdateFeatureEditorState();
}
void App_UIWindow::App_Func_RefreshFunctionStatus()
{
if (appFunctionLabelStatus != nullptr)
{
appFunctionLabelStatus->setText(
appLgcState.TextFunctionStatus.isEmpty()
? QStringLiteral("等待按键动作。")
: appLgcState.TextFunctionStatus);
}
}
void App_UIWindow::App_Func_RefreshDebugView()
{
#if APP_ENABLE_DEBUG_WINDOW
appDebugPanel->Debug_Func_SetConfigStatusText(
App_Func_GetDebugConfigStatusText(appLgcState),
App_Func_HasDebugSendRoute(appLgcState));
appDebugPanel->Debug_Func_SetConnectionText(
appLgcState.IsConnected ? QStringLiteral("连接成功") : QStringLiteral("连接失败"),
appLgcState.IsConnected);
appDebugPanel->Debug_Func_SetLogText(appLgcState.TextLog);
#endif
}
void App_UIWindow::App_Func_RefreshAfterLogicChange()
{
App_Func_RefreshKeypadState();
App_Func_RefreshDebugView();
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_SelectFeature(int FeatureId, bool SwitchToFeaturePage)
{
if (appIsSequenceRecording && (FeatureId != appSelectedFeatureId))
{
App_Func_StopSequenceRecording();
}
appSelectedFeatureId =
appLgcState.FunctionButtonConfig.FeatureMap.contains(FeatureId) ? FeatureId : 0;
if ((appFeatureTable != nullptr) && (appSelectedFeatureId > 0))
{
for (int Row = 0; Row < appFeatureTable->rowCount(); ++Row)
{
QTableWidgetItem* p_Item = appFeatureTable->item(Row, 0);
if ((p_Item != nullptr) && (p_Item->data(Qt::UserRole).toInt() == appSelectedFeatureId))
{
QSignalBlocker Blocker(appFeatureTable);
appFeatureTable->selectRow(Row);
break;
}
}
}
App_Func_UpdateFeatureEditorState();
if (SwitchToFeaturePage && (appPageTab != nullptr))
{
appPageTab->setCurrentIndex(appFeaturePageIndex);
}
}
void App_UIWindow::App_Func_SaveFeatureFromUi()
{
if (appSelectedFeatureId <= 0)
{
return;
}
Lgc_FunctionFeature_Definition Feature =
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
if (Feature.Id <= 0)
{
return;
}
Feature.Name = appFeatureNameEdit->text();
Feature.Description = appFeatureDescriptionEdit->text();
Feature.Type = static_cast<Lgc_FunctionFeature_Type>(appFeatureTypeCombo->currentData().toInt());
Feature.SequenceText = appFeatureSequenceEdit->text();
Feature.WebsiteUrl = appFeatureWebsiteEdit->text();
if ((Feature.Type == Lgc_FunctionFeature_Type::Website) &&
Feature.WebsiteUrl.trimmed().isEmpty())
{
Feature.WebsiteUrl = QStringLiteral("https://");
QSignalBlocker Blocker(appFeatureWebsiteEdit);
appFeatureWebsiteEdit->setText(Feature.WebsiteUrl);
}
Lgc_FunctionButton_SetFeature(&appLgcState.FunctionButtonConfig, Feature);
appFeatureEditorStack->setCurrentIndex(App_Func_GetFeatureStackIndex(Feature.Type));
App_Func_UpdateFeatureEditorHeight();
App_Func_RefreshFeatureTable();
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_UpdateFeatureEditorHeight()
{
if (appFeatureEditorStack == nullptr)
{
return;
}
QWidget* p_CurrentPage = appFeatureEditorStack->currentWidget();
if (p_CurrentPage == nullptr)
{
return;
}
const int AvailableWidth = qMax(
p_CurrentPage->contentsRect().width(),
appFeatureEditorStack->contentsRect().width());
int Height = p_CurrentPage->minimumSizeHint().height();
if (QLayout* p_Layout = p_CurrentPage->layout())
{
if ((AvailableWidth > 0) && p_Layout->hasHeightForWidth())
{
Height = qMax(Height, p_Layout->totalHeightForWidth(AvailableWidth));
}
Height = qMax(Height, p_Layout->sizeHint().height());
}
else
{
if ((AvailableWidth > 0) && p_CurrentPage->hasHeightForWidth())
{
Height = qMax(Height, p_CurrentPage->heightForWidth(AvailableWidth));
}
Height = qMax(Height, p_CurrentPage->sizeHint().height());
}
if (appFeatureEditorStack->height() != Height)
{
appFeatureEditorStack->setFixedHeight(Height);
}
}
void App_UIWindow::App_Func_UpdateFeatureEditorState()
{
const Lgc_FunctionFeature_Definition Feature =
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
const bool HasFeature = Feature.Id > 0;
if (appIsSequenceRecording && (!HasFeature || !App_Func_IsKeyRecordFeatureType(Feature.Type)))
{
App_Func_StopSequenceRecording();
}
appFeatureNameEdit->setEnabled(HasFeature);
appFeatureDescriptionEdit->setEnabled(HasFeature);
appFeatureTypeCombo->setEnabled(HasFeature);
appFeatureEditorStack->setEnabled(HasFeature);
if (appFeatureDeleteButton != nullptr)
{
appFeatureDeleteButton->setEnabled(HasFeature);
}
appIsUpdatingFeatureUi = true;
if (!HasFeature)
{
appFeatureNameEdit->clear();
appFeatureDescriptionEdit->clear();
appFeatureSequenceEdit->clear();
appFeatureWebsiteEdit->clear();
appFeatureTypeCombo->setCurrentIndex(0);
appFeatureEditorStack->setCurrentIndex(0);
App_Func_UpdateFeatureEditorHeight();
appFeatureBindingSummaryLabel->setText(QStringLiteral("当前还没有功能,请点击“添加功能”。"));
appIsUpdatingFeatureUi = false;
App_Func_UpdateSequenceRecordingUi();
return;
}
appFeatureNameEdit->setText(Feature.Name);
appFeatureDescriptionEdit->setText(Feature.Description);
const int TypeIndex = appFeatureTypeCombo->findData(static_cast<int>(Feature.Type));
if (TypeIndex >= 0)
{
appFeatureTypeCombo->setCurrentIndex(TypeIndex);
}
appFeatureSequenceEdit->setText(Feature.SequenceText);
appFeatureWebsiteEdit->setText(App_Func_GetWebsiteEditText(Feature.WebsiteUrl));
appFeatureEditorStack->setCurrentIndex(App_Func_GetFeatureStackIndex(Feature.Type));
appFeatureSequenceEdit->setPlaceholderText(
Feature.Type == Lgc_FunctionFeature_Type::KeySequence
? QStringLiteral("例如Ctrl+C -> Ctrl+A")
: QStringLiteral("例如Ctrl+C"));
App_Func_UpdateFeatureEditorHeight();
appFeatureBindingSummaryLabel->setText(App_Func_GetFeatureBindingSummary(Feature.Id));
appIsUpdatingFeatureUi = false;
App_Func_UpdateSequenceRecordingUi();
}
void App_UIWindow::App_Func_AddFeature()
{
const int FeatureId = Lgc_FunctionButton_AddFeature(&appLgcState.FunctionButtonConfig);
App_Func_RefreshFeatureTable();
App_Func_SelectFeature(FeatureId, true);
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_DeleteFeature()
{
if (appSelectedFeatureId <= 0)
{
return;
}
if (appIsSequenceRecording)
{
App_Func_StopSequenceRecording();
}
const QString FeatureName = App_Func_GetFeatureNameById(appSelectedFeatureId);
Lgc_FunctionButton_RemoveFeature(&appLgcState.FunctionButtonConfig, appSelectedFeatureId);
appSelectedFeatureId = 0;
Lgc_Core_ApplyFunctionConfig(&appLgcState);
appLgcState.TextFunctionStatus = QStringLiteral("已删除功能:%1").arg(FeatureName);
App_Func_RefreshFeatureTable();
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_AssignFeatureToUsage(quint16 Usage, int FeatureId)
{
if (FeatureId > 0 && !appLgcState.FunctionButtonConfig.FeatureMap.contains(FeatureId))
{
return;
}
Lgc_FunctionButton_SetUsageFeatureId(&appLgcState.FunctionButtonConfig, Usage, FeatureId);
Lgc_Core_ApplyFunctionConfig(&appLgcState);
appLgcState.TextFunctionStatus = FeatureId > 0
? QStringLiteral("已将按键 %1 绑定到 %2。")
.arg(Lgc_FunctionButton_GetUsageShortText(Usage), App_Func_GetFeatureNameById(FeatureId))
: QStringLiteral("已清除按键 %1 的功能绑定。")
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
App_Func_RefreshFeatureTable();
App_Func_RefreshUi();
}
QString App_UIWindow::App_Func_GetKeyHintText(const QString& KeyId) const
{
const quint16 Usage = appKeypadModel.App_Func_GetUsageFromKeyId(KeyId);
const int FeatureId = Lgc_FunctionButton_GetUsageFeatureId(appLgcState.FunctionButtonConfig, Usage);
return FeatureId > 0 ? App_Func_GetFeatureNameById(FeatureId) : appKeypadModel.App_Func_GetDefaultHint(KeyId);
}
QString App_UIWindow::App_Func_GetFeatureNameById(int FeatureId) const
{
const Lgc_FunctionFeature_Definition Feature =
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, FeatureId);
return Feature.Id > 0 ? Lgc_FunctionButton_GetFeatureName(Feature) : QStringLiteral("无功能");
}
QString App_UIWindow::App_Func_GetFeatureDescriptionById(int FeatureId) const
{
const Lgc_FunctionFeature_Definition Feature =
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, FeatureId);
if (Feature.Id <= 0)
{
return QStringLiteral("未绑定功能。");
}
if (!Feature.Description.trimmed().isEmpty())
{
return Feature.Description.trimmed();
}
switch (Feature.Type)
{
case Lgc_FunctionFeature_Type::KeyCombination:
return Feature.SequenceText.trimmed().isEmpty()
? QStringLiteral("输出一次快捷键,当前还没有配置快捷键。")
: QStringLiteral("输出快捷键:%1").arg(Feature.SequenceText.trimmed());
case Lgc_FunctionFeature_Type::KeySequence:
return Feature.SequenceText.trimmed().isEmpty()
? QStringLiteral("按顺序输出多组快捷键,当前还没有配置序列。")
: QStringLiteral("输出快捷键序列:%1").arg(Feature.SequenceText.trimmed());
case Lgc_FunctionFeature_Type::Website:
return Feature.WebsiteUrl.trimmed().isEmpty()
? QStringLiteral("打开网址,当前还没有配置链接。")
: QStringLiteral("打开网址:%1").arg(Feature.WebsiteUrl.trimmed());
default:
return QStringLiteral("未知功能。");
}
}
QString App_UIWindow::App_Func_GetFeatureDescriptionForUsage(quint16 Usage) const
{
const int FeatureId = Lgc_FunctionButton_GetUsageFeatureId(appLgcState.FunctionButtonConfig, Usage);
return FeatureId > 0 ? App_Func_GetFeatureDescriptionById(FeatureId) : App_Func_GetDefaultKeyDescription(Usage);
}
QString App_UIWindow::App_Func_GetDefaultKeyDescription(quint16 Usage) const
{
return QStringLiteral("默认小键盘按键:%1。左键模拟真实按下右键可以绑定功能。")
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
}
QString App_UIWindow::App_Func_GetFeatureBindingSummary(int FeatureId) const
{
if (FeatureId <= 0)
{
return QStringLiteral("当前未绑定任何按键。");
}
QStringList KeyList;
for (quint16 Usage : Lgc_FunctionButton_GetConfigurableUsages())
{
if (Lgc_FunctionButton_GetUsageFeatureId(appLgcState.FunctionButtonConfig, Usage) == FeatureId)
{
KeyList.append(Lgc_FunctionButton_GetUsageShortText(Usage));
}
}
return KeyList.isEmpty()
? QStringLiteral("当前未绑定任何按键。")
: QStringLiteral("当前绑定按键:%1").arg(KeyList.join(QStringLiteral(", ")));
}
void App_UIWindow::App_Func_OnPollTimer()
{
if (Lgc_Core_Poll(&appLgcState))
{
App_Func_RefreshAfterLogicChange();
}
}
#if APP_ENABLE_DEBUG_WINDOW
void App_UIWindow::App_Func_RefreshDeviceConfigFromState()
{
appDebugPanel->Debug_Func_SetDeviceConfigText(
appLgcState.DeviceConfig.VendorId,
appLgcState.DeviceConfig.ProductId);
appDebugPanel->Debug_Func_SetConfigStatusText(
App_Func_GetDebugConfigStatusText(appLgcState),
App_Func_HasDebugSendRoute(appLgcState));
}
void App_UIWindow::App_Func_OnApplyDeviceConfigClicked()
{
quint16 VendorId = 0;
quint16 ProductId = 0;
if (!appDebugPanel->Debug_Func_TryGetDeviceConfig(&VendorId, &ProductId))
{
appDebugPanel->Debug_Func_SetConfigStatusText(
QStringLiteral("VID / PID 输入无效。请使用十六进制。"),
false);
return;
}
appLgcState.DeviceConfig.VendorId = VendorId;
appLgcState.DeviceConfig.ProductId = ProductId;
App_Func_OnRefreshDeviceClicked();
}
void App_UIWindow::App_Func_OnRefreshDeviceClicked()
{
Lgc_Core_RefreshDevice(&appLgcState);
App_Func_RefreshDeviceConfigFromState();
App_Func_RefreshAfterLogicChange();
}
void App_UIWindow::App_Func_OnClearLogClicked()
{
Lgc_Core_ClearLog(&appLgcState);
App_Func_RefreshDebugView();
}
void App_UIWindow::App_Func_OnSyncTimeClicked()
{
Lgc_Core_SendTimeSync(&appLgcState);
App_Func_RefreshAfterLogicChange();
}
void App_UIWindow::App_Func_OnModeSwitchClicked()
{
Lgc_Core_SendThemeSwitch(&appLgcState);
App_Func_RefreshAfterLogicChange();
}
#endif
} // namespace APP

View File

@@ -0,0 +1,12 @@
#pragma once
#include "LOGIC/Lgc_Func_Button.h"
#include <QtCore/QString>
namespace APP {
int App_Func_GetFeatureStackIndex(Lgc_FunctionFeature_Type Type);
bool App_Func_IsKeyRecordFeatureType(Lgc_FunctionFeature_Type Type);
QString App_Func_GetWebsiteEditText(const QString& UrlText);
} // namespace APP

558
APP/APP_UIWindow_Record.cpp Normal file
View File

@@ -0,0 +1,558 @@
#include "APP/APP_UIWindow.h"
#include "APP/APP_UIWindow_Private.h"
#include <QtCore/QByteArray>
#include <QtCore/QSignalBlocker>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMenu>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTableWidget>
#include <Windows.h>
namespace APP {
namespace
{
bool App_Func_IsModifierRecordToken(const QString& Token)
{
return (Token == QStringLiteral("Ctrl")) ||
(Token == QStringLiteral("Shift")) ||
(Token == QStringLiteral("Alt")) ||
(Token == QStringLiteral("Win"));
}
QStringList App_Func_GetOrderedRecordedModifierTokens(const QSet<QString>& PressedKeySet)
{
const QStringList ModifierOrder = {
QStringLiteral("Ctrl"),
QStringLiteral("Shift"),
QStringLiteral("Alt"),
QStringLiteral("Win")
};
QStringList Result;
for (const QString& ModifierToken : ModifierOrder)
{
if (PressedKeySet.contains(ModifierToken))
{
Result.append(ModifierToken);
}
}
return Result;
}
QString App_Func_GetRecordedCombinationText(
const QSet<QString>& PressedKeySet,
const QString& TriggerToken)
{
QStringList TokenList = App_Func_GetOrderedRecordedModifierTokens(PressedKeySet);
if (!TriggerToken.isEmpty() && !App_Func_IsModifierRecordToken(TriggerToken))
{
TokenList.append(TriggerToken);
}
return TokenList.join(QStringLiteral("+"));
}
bool App_Func_TryGetRawKeyboard(void* p_Message, RAWKEYBOARD* p_Keyboard)
{
if ((p_Message == nullptr) || (p_Keyboard == nullptr))
{
return false;
}
MSG* p_Msg = reinterpret_cast<MSG*>(p_Message);
if (p_Msg->message != WM_INPUT)
{
return false;
}
UINT NeedSize = 0;
GetRawInputData(
reinterpret_cast<HRAWINPUT>(p_Msg->lParam),
RID_INPUT,
nullptr,
&NeedSize,
sizeof(RAWINPUTHEADER));
if (NeedSize == 0)
{
return false;
}
QByteArray Buffer(static_cast<int>(NeedSize), 0);
if (GetRawInputData(
reinterpret_cast<HRAWINPUT>(p_Msg->lParam),
RID_INPUT,
Buffer.data(),
&NeedSize,
sizeof(RAWINPUTHEADER)) == static_cast<UINT>(-1))
{
return false;
}
const RAWINPUT* p_Input = reinterpret_cast<const RAWINPUT*>(Buffer.constData());
if (p_Input->header.dwType != RIM_TYPEKEYBOARD)
{
return false;
}
*p_Keyboard = p_Input->data.keyboard;
return true;
}
QString App_Func_GetRecordedKeyToken(const RAWKEYBOARD& Keyboard)
{
const bool IsE0 = (Keyboard.Flags & RI_KEY_E0) != 0;
const USHORT VirtualKey = Keyboard.VKey;
if ((VirtualKey >= 'A') && (VirtualKey <= 'Z'))
{
return QString(QChar(static_cast<char16_t>(VirtualKey)));
}
if ((VirtualKey >= '0') && (VirtualKey <= '9'))
{
return QString(QChar(static_cast<char16_t>(VirtualKey)));
}
if ((VirtualKey >= VK_F1) && (VirtualKey <= VK_F24))
{
return QStringLiteral("F%1").arg(VirtualKey - VK_F1 + 1);
}
switch (VirtualKey)
{
case VK_CONTROL:
case VK_LCONTROL:
case VK_RCONTROL:
return QStringLiteral("Ctrl");
case VK_SHIFT:
case VK_LSHIFT:
case VK_RSHIFT:
return QStringLiteral("Shift");
case VK_MENU:
case VK_LMENU:
case VK_RMENU:
return QStringLiteral("Alt");
case VK_LWIN:
case VK_RWIN:
return QStringLiteral("Win");
case VK_RETURN:
return IsE0 ? QStringLiteral("NumEnter") : QStringLiteral("Enter");
case VK_SPACE:
return QStringLiteral("Space");
case VK_TAB:
return QStringLiteral("Tab");
case VK_ESCAPE:
return QStringLiteral("Esc");
case VK_BACK:
return QStringLiteral("Backspace");
case VK_DELETE:
return QStringLiteral("Delete");
case VK_INSERT:
return QStringLiteral("Insert");
case VK_HOME:
return QStringLiteral("Home");
case VK_END:
return QStringLiteral("End");
case VK_PRIOR:
return QStringLiteral("PageUp");
case VK_NEXT:
return QStringLiteral("PageDown");
case VK_LEFT:
return QStringLiteral("Left");
case VK_RIGHT:
return QStringLiteral("Right");
case VK_UP:
return QStringLiteral("Up");
case VK_DOWN:
return QStringLiteral("Down");
case VK_CAPITAL:
return QStringLiteral("CapsLock");
case VK_SNAPSHOT:
return QStringLiteral("PrintScreen");
case VK_SCROLL:
return QStringLiteral("ScrollLock");
case VK_PAUSE:
return QStringLiteral("Pause");
case VK_NUMPAD0:
return QStringLiteral("Num0");
case VK_NUMPAD1:
return QStringLiteral("Num1");
case VK_NUMPAD2:
return QStringLiteral("Num2");
case VK_NUMPAD3:
return QStringLiteral("Num3");
case VK_NUMPAD4:
return QStringLiteral("Num4");
case VK_NUMPAD5:
return QStringLiteral("Num5");
case VK_NUMPAD6:
return QStringLiteral("Num6");
case VK_NUMPAD7:
return QStringLiteral("Num7");
case VK_NUMPAD8:
return QStringLiteral("Num8");
case VK_NUMPAD9:
return QStringLiteral("Num9");
case VK_DIVIDE:
return QStringLiteral("Num/");
case VK_MULTIPLY:
return QStringLiteral("Num*");
case VK_SUBTRACT:
return QStringLiteral("Num-");
case VK_ADD:
return QStringLiteral("Num+");
case VK_DECIMAL:
return QStringLiteral("Num.");
case VK_OEM_COMMA:
return QStringLiteral("Comma");
case VK_OEM_PERIOD:
return QStringLiteral("Period");
case VK_OEM_1:
return QStringLiteral("Semicolon");
case VK_OEM_2:
return QStringLiteral("Slash");
case VK_OEM_3:
return QStringLiteral("Grave");
case VK_OEM_4:
return QStringLiteral("LeftBracket");
case VK_OEM_5:
return QStringLiteral("Backslash");
case VK_OEM_6:
return QStringLiteral("RightBracket");
case VK_OEM_7:
return QStringLiteral("Quote");
case VK_OEM_MINUS:
return QStringLiteral("Minus");
case VK_OEM_PLUS:
return QStringLiteral("Equal");
default:
return QString();
}
}
} // namespace
void App_UIWindow::App_Func_StartSequenceRecording()
{
const Lgc_FunctionFeature_Definition Feature =
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
if (Feature.Id <= 0 || !App_Func_IsKeyRecordFeatureType(Feature.Type))
{
return;
}
appIsSequenceRecording = true;
appSequenceRecordingPressedKeySet.clear();
appLgcState.IsFunctionSequenceRecording = true;
{
QSignalBlocker Blocker(appFeatureSequenceEdit);
appFeatureSequenceEdit->setText(QString());
}
App_Func_SaveFeatureFromUi();
appLgcState.TextFunctionStatus =
Feature.Type == Lgc_FunctionFeature_Type::KeySequence
? QStringLiteral("已开始录入快捷键序列,接下来按下任意键盘按键即可按组追加。")
: QStringLiteral("已开始录入快捷键,请按下目标组合键。");
App_Func_UpdateSequenceRecordingUi();
if (appFeatureSequenceEdit != nullptr)
{
appFeatureSequenceEdit->setFocus(Qt::OtherFocusReason);
}
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_StopSequenceRecording()
{
appIsSequenceRecording = false;
appSequenceRecordingPressedKeySet.clear();
appLgcState.IsFunctionSequenceRecording = false;
appLgcState.TextFunctionStatus = QStringLiteral("已退出录入,当前功能键配置已保存。");
App_Func_UpdateSequenceRecordingUi();
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_UpdateSequenceRecordingUi()
{
const Lgc_FunctionFeature_Definition Feature =
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
const bool HasFeature = Feature.Id > 0;
const bool CanRecord =
HasFeature && App_Func_IsKeyRecordFeatureType(Feature.Type);
const bool IsLocked = appIsSequenceRecording;
if (appFeatureTable != nullptr)
{
appFeatureTable->setEnabled(!IsLocked);
}
if (appFeatureAddButton != nullptr)
{
appFeatureAddButton->setEnabled(!IsLocked);
}
if (appFeatureDeleteButton != nullptr)
{
appFeatureDeleteButton->setEnabled(HasFeature && !IsLocked);
}
if (appFeatureNameEdit != nullptr)
{
appFeatureNameEdit->setEnabled(HasFeature && !IsLocked);
}
if (appFeatureDescriptionEdit != nullptr)
{
appFeatureDescriptionEdit->setEnabled(HasFeature && !IsLocked);
}
if (appFeatureTypeCombo != nullptr)
{
appFeatureTypeCombo->setEnabled(HasFeature && !IsLocked);
}
if (appFeatureWebsiteEdit != nullptr)
{
appFeatureWebsiteEdit->setEnabled(HasFeature && !IsLocked);
}
if (appFeatureSequenceEdit != nullptr)
{
appFeatureSequenceEdit->setReadOnly(appIsSequenceRecording);
}
if (appFeatureSequenceRecordStartButton != nullptr)
{
appFeatureSequenceRecordStartButton->setEnabled(CanRecord && !appIsSequenceRecording);
}
if (appFeatureSequenceRecordStopButton != nullptr)
{
appFeatureSequenceRecordStopButton->setEnabled(CanRecord && appIsSequenceRecording);
}
}
bool App_UIWindow::App_Func_HandleSequenceRecordMessage(void* p_Message)
{
if (!appIsSequenceRecording)
{
return false;
}
RAWKEYBOARD Keyboard = {};
if (!App_Func_TryGetRawKeyboard(p_Message, &Keyboard))
{
return false;
}
const QString Token = App_Func_GetRecordedKeyToken(Keyboard);
if (Token.isEmpty())
{
return false;
}
const bool IsPressed = (Keyboard.Flags & RI_KEY_BREAK) == 0;
if (IsPressed)
{
if (appSequenceRecordingPressedKeySet.contains(Token))
{
return false;
}
appSequenceRecordingPressedKeySet.insert(Token);
if (!App_Func_IsModifierRecordToken(Token))
{
App_Func_AppendRecordedSequenceToken(Token);
return true;
}
return false;
}
appSequenceRecordingPressedKeySet.remove(Token);
return false;
}
void App_UIWindow::App_Func_AppendRecordedSequenceToken(const QString& Token)
{
if (Token.isEmpty() || appFeatureSequenceEdit == nullptr)
{
return;
}
const Lgc_FunctionFeature_Definition Feature =
Lgc_FunctionButton_GetFeature(appLgcState.FunctionButtonConfig, appSelectedFeatureId);
if (Feature.Id <= 0 || !App_Func_IsKeyRecordFeatureType(Feature.Type))
{
return;
}
const QString CombinationText =
App_Func_GetRecordedCombinationText(appSequenceRecordingPressedKeySet, Token);
if (CombinationText.isEmpty())
{
return;
}
const QString OldText = appFeatureSequenceEdit->text().trimmed();
const QString NewText =
Feature.Type == Lgc_FunctionFeature_Type::KeySequence
? (OldText.isEmpty()
? CombinationText
: QStringLiteral("%1 -> %2").arg(OldText, CombinationText))
: CombinationText;
{
QSignalBlocker Blocker(appFeatureSequenceEdit);
appFeatureSequenceEdit->setText(NewText);
appFeatureSequenceEdit->setCursorPosition(NewText.size());
}
App_Func_SaveFeatureFromUi();
appLgcState.TextFunctionStatus = QStringLiteral("录入中:%1").arg(NewText);
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_HandleUiKeyPressed(quint16 Usage)
{
QString TextStatus;
if (Lgc_FunctionButton_HasUsageFeature(appLgcState.FunctionButtonConfig, Usage))
{
if (!Lgc_FunctionButton_RunBinding(&appLgcState, Usage, &TextStatus))
{
TextStatus = QStringLiteral("%1 当前没有可执行功能。")
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
}
}
else
{
if (Lgc_FunctionButton_SendUsageToWindows(Usage, true))
{
appUiPressedUsageSet.insert(Usage);
TextStatus = QStringLiteral("已模拟按下 %1。")
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
}
else
{
TextStatus = QStringLiteral("模拟按下 %1 失败。")
.arg(Lgc_FunctionButton_GetUsageShortText(Usage));
}
}
if (!TextStatus.isEmpty())
{
appLgcState.TextFunctionStatus = TextStatus;
}
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_HandleUiKeyReleased(quint16 Usage)
{
if (!appUiPressedUsageSet.remove(Usage))
{
return;
}
appLgcState.TextFunctionStatus =
Lgc_FunctionButton_SendUsageToWindows(Usage, false)
? QStringLiteral("已模拟抬起 %1。").arg(Lgc_FunctionButton_GetUsageShortText(Usage))
: QStringLiteral("模拟抬起 %1 失败。").arg(Lgc_FunctionButton_GetUsageShortText(Usage));
App_Func_RefreshUi();
}
void App_UIWindow::App_Func_ShowKeyMenu(quint16 Usage, const QPoint& GlobalPos)
{
const int CurrentFeatureId =
Lgc_FunctionButton_GetUsageFeatureId(appLgcState.FunctionButtonConfig, Usage);
QMenu Menu(this);
QAction* p_NoneAction = Menu.addAction(QStringLiteral("无功能"));
p_NoneAction->setCheckable(true);
p_NoneAction->setChecked(CurrentFeatureId <= 0);
p_NoneAction->setData(0);
const QVector<int> FeatureIdList =
Lgc_FunctionButton_GetFeatureIdList(appLgcState.FunctionButtonConfig);
if (!FeatureIdList.isEmpty())
{
Menu.addSeparator();
for (int FeatureId : FeatureIdList)
{
QAction* p_Action = Menu.addAction(QStringLiteral("绑定到 %1").arg(App_Func_GetFeatureNameById(FeatureId)));
p_Action->setCheckable(true);
p_Action->setChecked(FeatureId == CurrentFeatureId);
p_Action->setData(FeatureId);
p_Action->setToolTip(App_Func_GetFeatureDescriptionById(FeatureId));
}
}
else
{
Menu.addSeparator();
QAction* p_EmptyAction = Menu.addAction(QStringLiteral("暂无功能,请先到功能表添加"));
p_EmptyAction->setEnabled(false);
}
Menu.addSeparator();
QAction* p_OpenFeaturePageAction = Menu.addAction(QStringLiteral("打开功能表"));
p_OpenFeaturePageAction->setData(-1);
QAction* p_SelectedAction = Menu.exec(GlobalPos);
if (p_SelectedAction == nullptr)
{
return;
}
const int ActionData = p_SelectedAction->data().toInt();
if (ActionData == -1)
{
App_Func_SelectFeature(CurrentFeatureId, true);
return;
}
App_Func_AssignFeatureToUsage(Usage, ActionData);
if (ActionData > 0)
{
App_Func_SelectFeature(ActionData);
}
}
} // namespace APP