Files
0417_QT_code/DRI/Dri_Vendor.cpp

339 lines
9.1 KiB
C++
Raw Normal View History

2026-03-26 10:45:29 +08:00
#include "DRI/Dri_Vendor.h"
#include <hidsdi.h>
#pragma comment(lib, "hid.lib")
namespace
{
/* ---------- 句柄与状态小工具 ---------- */
void Dri_Vendor_Func_SetStatus(QString* p_TextStatus, const QString& Text)
{
if (p_TextStatus != nullptr)
{
*p_TextStatus = Text;
}
}
HANDLE Dri_Vendor_Func_OpenHandle(const QString& DevicePath, DWORD DesiredAccess, DWORD Flags)
{
return CreateFileW(
reinterpret_cast<LPCWSTR>(DevicePath.utf16()),
DesiredAccess,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr,
OPEN_EXISTING,
Flags,
nullptr);
}
bool Dri_Vendor_Func_BeginRead(Dri_Vendor_Struct_Port* p_Port, QString* p_TextStatus)
{
if (!p_Port->IsOpened || (p_Port->InputLength == 0))
{
return false;
}
if (p_Port->IsReadPending)
{
return true;
}
ResetEvent(p_Port->HandleEvent);
p_Port->ReadBuffer.fill(0, p_Port->InputLength);
p_Port->OverlappedRead = {};
p_Port->OverlappedRead.hEvent = p_Port->HandleEvent;
DWORD BytesRead = 0;
if (ReadFile(
p_Port->HandleRead,
p_Port->ReadBuffer.data(),
p_Port->InputLength,
&BytesRead,
&p_Port->OverlappedRead) ||
(GetLastError() == ERROR_IO_PENDING))
{
p_Port->IsReadPending = true;
return true;
}
Dri_Vendor_Func_SetStatus(
p_TextStatus,
QStringLiteral("Vendor 接口启动异步读取失败:%1").arg(GetLastError()));
return false;
}
HANDLE Dri_Vendor_Func_OpenWriteHandle(const QString& DevicePath, QString* p_TextError)
{
HANDLE HandleWrite = Dri_Vendor_Func_OpenHandle(DevicePath, GENERIC_WRITE, 0);
if (HandleWrite != INVALID_HANDLE_VALUE)
{
return HandleWrite;
}
const DWORD WriteError = GetLastError();
HandleWrite = Dri_Vendor_Func_OpenHandle(DevicePath, 0, 0);
if ((HandleWrite == INVALID_HANDLE_VALUE) && (p_TextError != nullptr))
{
*p_TextError = QStringLiteral("GENERIC_WRITE=%1ZeroAccess=%2")
.arg(WriteError)
.arg(GetLastError());
}
return HandleWrite;
}
bool Dri_Vendor_Func_TryWritePacket(
HANDLE HandleWrite,
quint16 OutputLength,
const QByteArray& Packet,
QString* p_TextError)
{
if ((HandleWrite == INVALID_HANDLE_VALUE) || Packet.isEmpty())
{
return false;
}
QByteArray Buffer = Packet;
if ((OutputLength > 0) && (Buffer.size() < OutputLength))
{
Buffer.append(OutputLength - Buffer.size(), 0);
}
if (HidD_SetOutputReport(HandleWrite, Buffer.data(), static_cast<ULONG>(Buffer.size())))
{
return true;
}
const DWORD SetReportError = GetLastError();
DWORD BytesWritten = 0;
if (WriteFile(
HandleWrite,
Buffer.constData(),
static_cast<DWORD>(Buffer.size()),
&BytesWritten,
nullptr) &&
(BytesWritten == static_cast<DWORD>(Buffer.size())))
{
return true;
}
if (p_TextError != nullptr)
{
*p_TextError = QStringLiteral("SetOutputReport=%1WriteFile=%2")
.arg(SetReportError)
.arg(GetLastError());
}
return false;
}
} // namespace
/* ---------- 生命周期 ---------- */
void Dri_Vendor_Func_Close(Dri_Vendor_Struct_Port* p_Port)
{
if ((p_Port->HandleRead != INVALID_HANDLE_VALUE) && p_Port->IsReadPending)
{
CancelIoEx(p_Port->HandleRead, &p_Port->OverlappedRead);
}
for (HANDLE* p_Handle : { &p_Port->HandleRead, &p_Port->HandleWriteVendor, &p_Port->HandleWriteNkro, &p_Port->HandleEvent })
{
if ((*p_Handle != nullptr) && (*p_Handle != INVALID_HANDLE_VALUE))
{
CloseHandle(*p_Handle);
}
}
*p_Port = Dri_Vendor_Struct_Port();
}
bool Dri_Vendor_Func_Open(
Dri_Vendor_Struct_Port* p_Port,
const Mid_Struct_DeviceConfig& DeviceConfig,
QString* p_TextStatus)
{
Dri_Vendor_Func_Close(p_Port);
QString VendorPath;
quint16 InputLength = 0;
quint16 OutputLength = 0;
if (!Mid_Func_FindHidInterface(
Mid_Func_GetVendorMatch(DeviceConfig),
&VendorPath,
&InputLength,
&OutputLength))
{
Dri_Vendor_Func_SetStatus(p_TextStatus, QStringLiteral("未找到 Vendor 接口FF00 / 0002。"));
return false;
}
p_Port->HandleRead = Dri_Vendor_Func_OpenHandle(VendorPath, GENERIC_READ, FILE_FLAG_OVERLAPPED);
if (p_Port->HandleRead == INVALID_HANDLE_VALUE)
{
Dri_Vendor_Func_SetStatus(
p_TextStatus,
QStringLiteral("Vendor 接口打开读句柄失败:%1").arg(GetLastError()));
return false;
}
p_Port->HandleEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
if (p_Port->HandleEvent == nullptr)
{
Dri_Vendor_Func_SetStatus(
p_TextStatus,
QStringLiteral("Vendor 接口创建事件失败:%1").arg(GetLastError()));
Dri_Vendor_Func_Close(p_Port);
return false;
}
p_Port->HandleWriteVendor = Dri_Vendor_Func_OpenWriteHandle(VendorPath, nullptr);
QString NkroPath;
quint16 NkroOutputLength = 0;
if (Mid_Func_FindHidInterface(
Mid_Func_GetNkroMatch(DeviceConfig),
&NkroPath,
nullptr,
&NkroOutputLength))
{
QString TextError;
p_Port->HandleWriteNkro = Dri_Vendor_Func_OpenWriteHandle(NkroPath, &TextError);
p_Port->NkroWriteOutputLength = NkroOutputLength;
if (p_Port->HandleWriteNkro == INVALID_HANDLE_VALUE)
{
Dri_Vendor_Func_SetStatus(
p_TextStatus,
QStringLiteral("Vendor 读链路已打开,但 NKRO 写句柄打开失败:%1").arg(TextError));
}
}
else
{
Dri_Vendor_Func_SetStatus(
p_TextStatus,
QStringLiteral("Vendor 读链路已打开,但没有找到 NKRO 写接口。"));
}
p_Port->InputLength = InputLength;
p_Port->OutputLength = OutputLength;
p_Port->ReadBuffer = QByteArray(InputLength, 0);
p_Port->OverlappedRead.hEvent = p_Port->HandleEvent;
p_Port->IsOpened = true;
if (!Dri_Vendor_Func_BeginRead(p_Port, p_TextStatus))
{
Dri_Vendor_Func_Close(p_Port);
return false;
}
return true;
}
/* ---------- 读写流程 ---------- */
bool Dri_Vendor_Func_Read(
Dri_Vendor_Struct_Port* p_Port,
Mid_Struct_RawPacket* p_Packet,
QString* p_TextStatus)
{
*p_Packet = Mid_Struct_RawPacket();
p_Packet->PortName = QStringLiteral("Vendor");
if (!p_Port->IsOpened)
{
return false;
}
if (!p_Port->IsReadPending)
{
Dri_Vendor_Func_BeginRead(p_Port, p_TextStatus);
return false;
}
DWORD BytesRead = 0;
if (!GetOverlappedResult(p_Port->HandleRead, &p_Port->OverlappedRead, &BytesRead, FALSE))
{
const DWORD ErrorCode = GetLastError();
if (ErrorCode == ERROR_IO_INCOMPLETE)
{
return false;
}
Dri_Vendor_Func_SetStatus(
p_TextStatus,
QStringLiteral("Vendor 接口读包失败:%1").arg(ErrorCode));
Dri_Vendor_Func_Close(p_Port);
return false;
}
p_Port->IsReadPending = false;
if (BytesRead > 0)
{
p_Packet->IsValid = true;
p_Packet->ByteArray = p_Port->ReadBuffer.left(static_cast<int>(BytesRead));
}
Dri_Vendor_Func_BeginRead(p_Port, p_TextStatus);
return p_Packet->IsValid;
}
bool Dri_Vendor_Func_Write(
Dri_Vendor_Struct_Port* p_Port,
const QByteArray& ByteArray,
QString* p_TextStatus)
{
if (!p_Port->IsOpened)
{
Dri_Vendor_Func_SetStatus(
p_TextStatus,
QStringLiteral("Vendor 读链路未打开,不能发送掩码。"));
return false;
}
QStringList Errors;
const auto TryWriteTo = [&](HANDLE HandleWrite,
quint16 OutputLength,
const QString& SuccessText,
const QString& ErrorPrefix)
{
QString TextError;
if (Dri_Vendor_Func_TryWritePacket(HandleWrite, OutputLength, ByteArray, &TextError))
{
Dri_Vendor_Func_SetStatus(p_TextStatus, SuccessText);
return true;
}
if (!TextError.isEmpty())
{
Errors.append(ErrorPrefix.arg(TextError));
}
return false;
};
if (TryWriteTo(
p_Port->HandleWriteNkro,
p_Port->NkroWriteOutputLength,
QStringLiteral("掩码已发送到 NKRO 写接口。"),
QStringLiteral("NKRO 写接口发送失败:%1")))
{
return true;
}
if (TryWriteTo(
p_Port->HandleWriteVendor,
p_Port->OutputLength,
QStringLiteral("掩码已发送到 Vendor 写接口。"),
QStringLiteral("Vendor 写接口发送失败:%1")))
{
return true;
}
Dri_Vendor_Func_SetStatus(
p_TextStatus,
Errors.isEmpty()
? QStringLiteral("没有可用的写句柄,掩码发送未执行。")
: Errors.join(QStringLiteral("\n")));
return false;
}