Files
0417_QT_code/DRI/Dri_Vendor.cpp
2026-03-26 10:45:29 +08:00

339 lines
9.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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;
}