#include "DRI/Dri_Vendor.h" #include #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(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=%1,ZeroAccess=%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(Buffer.size()))) { return true; } const DWORD SetReportError = GetLastError(); DWORD BytesWritten = 0; if (WriteFile( HandleWrite, Buffer.constData(), static_cast(Buffer.size()), &BytesWritten, nullptr) && (BytesWritten == static_cast(Buffer.size()))) { return true; } if (p_TextError != nullptr) { *p_TextError = QStringLiteral("SetOutputReport=%1,WriteFile=%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(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; }