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

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