Push layered Qt host source files
This commit is contained in:
@@ -1,338 +1,248 @@
|
||||
#include "DRI/Dri_Vendor.h"
|
||||
#include "DRI/Dri_Vendor.h"
|
||||
|
||||
#include <hidsdi.h>
|
||||
|
||||
#pragma comment(lib, "hid.lib")
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/* ---------- 句柄与状态小工具 ---------- */
|
||||
|
||||
void Dri_Vendor_Func_SetStatus(QString* p_TextStatus, const QString& Text)
|
||||
void Dri_Vendor_CloseHandle(HANDLE* p_Handle)
|
||||
{
|
||||
if (p_TextStatus != nullptr)
|
||||
if ((*p_Handle != nullptr) && (*p_Handle != INVALID_HANDLE_VALUE))
|
||||
{
|
||||
*p_TextStatus = Text;
|
||||
CloseHandle(*p_Handle);
|
||||
}
|
||||
*p_Handle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
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=%1,ZeroAccess=%2")
|
||||
.arg(WriteError)
|
||||
.arg(GetLastError());
|
||||
}
|
||||
return HandleWrite;
|
||||
}
|
||||
|
||||
bool Dri_Vendor_Func_TryWritePacket(
|
||||
bool Dri_Vendor_TryWrite(
|
||||
HANDLE HandleWrite,
|
||||
quint16 OutputLength,
|
||||
const QByteArray& Packet,
|
||||
QString* p_TextError)
|
||||
const QString& SuccessText,
|
||||
const QString& ErrorPrefix,
|
||||
QString* p_TextStatus,
|
||||
QStringList* p_ErrorList)
|
||||
{
|
||||
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())))
|
||||
QString TextError;
|
||||
if (Dri_Hid_WritePacket(HandleWrite, OutputLength, Packet, &TextError))
|
||||
{
|
||||
if (p_TextStatus != nullptr)
|
||||
{
|
||||
*p_TextStatus = SuccessText;
|
||||
}
|
||||
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())))
|
||||
if (!TextError.isEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (p_TextError != nullptr)
|
||||
{
|
||||
*p_TextError = QStringLiteral("SetOutputReport=%1,WriteFile=%2")
|
||||
.arg(SetReportError)
|
||||
.arg(GetLastError());
|
||||
p_ErrorList->append(ErrorPrefix.arg(TextError));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/* ---------- 生命周期 ---------- */
|
||||
|
||||
void Dri_Vendor_Func_Close(Dri_Vendor_Struct_Port* p_Port)
|
||||
void Dri_Vendor_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();
|
||||
Dri_Hid_CloseReadPort(&p_Port->ReadPort);
|
||||
Dri_Vendor_CloseHandle(&p_Port->HandleWriteVendor);
|
||||
Dri_Vendor_CloseHandle(&p_Port->HandleWriteCommand);
|
||||
Dri_Vendor_CloseHandle(&p_Port->HandleWriteNkro);
|
||||
p_Port->VendorWriteOutputLength = 0;
|
||||
p_Port->CommandWriteOutputLength = 0;
|
||||
p_Port->NkroWriteOutputLength = 0;
|
||||
p_Port->IsBluetoothTransport = false;
|
||||
}
|
||||
|
||||
bool Dri_Vendor_Func_Open(
|
||||
bool Dri_Vendor_Init(
|
||||
Dri_Vendor_Struct_Port* p_Port,
|
||||
const Mid_Struct_DeviceConfig& DeviceConfig,
|
||||
QString* p_TextStatus)
|
||||
{
|
||||
Dri_Vendor_Func_Close(p_Port);
|
||||
Dri_Vendor_Close(p_Port);
|
||||
|
||||
Mid_Struct_DeviceMatch VendorMatch;
|
||||
VendorMatch.VendorId = DeviceConfig.VendorId;
|
||||
VendorMatch.ProductId = DeviceConfig.ProductId;
|
||||
VendorMatch.UsagePage = MID_CONST_USAGE_PAGE_VENDOR;
|
||||
VendorMatch.Usage = MID_CONST_USAGE_VENDOR;
|
||||
|
||||
QString VendorPath;
|
||||
QString VendorInstanceId;
|
||||
quint16 InputLength = 0;
|
||||
quint16 OutputLength = 0;
|
||||
if (!Mid_Func_FindHidInterface(
|
||||
Mid_Func_GetVendorMatch(DeviceConfig),
|
||||
quint16 VendorOutputLength = 0;
|
||||
if (!Mid_FindHidInterface(
|
||||
VendorMatch,
|
||||
&VendorPath,
|
||||
&InputLength,
|
||||
&OutputLength))
|
||||
&VendorOutputLength,
|
||||
&VendorInstanceId))
|
||||
{
|
||||
Dri_Vendor_Func_SetStatus(p_TextStatus, QStringLiteral("未找到 Vendor 接口:FF00 / 0002。"));
|
||||
if (p_TextStatus != nullptr)
|
||||
{
|
||||
*p_TextStatus = QStringLiteral("Vendor interface was not found: FF00 / 0002.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
p_Port->HandleRead = Dri_Vendor_Func_OpenHandle(VendorPath, GENERIC_READ, FILE_FLAG_OVERLAPPED);
|
||||
if (p_Port->HandleRead == INVALID_HANDLE_VALUE)
|
||||
p_Port->IsBluetoothTransport = Mid_IsBluetoothHidInstanceId(VendorInstanceId);
|
||||
const QString VendorPortName = p_Port->IsBluetoothTransport
|
||||
? QStringLiteral("Bluetooth/HID Vendor")
|
||||
: QStringLiteral("Vendor");
|
||||
|
||||
if (!Dri_Hid_InitReadPort(
|
||||
&p_Port->ReadPort,
|
||||
VendorPath,
|
||||
InputLength,
|
||||
Mid_Enum_RawPacketSource_UsbVendorHid,
|
||||
VendorPortName,
|
||||
p_TextStatus))
|
||||
{
|
||||
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_Hid_OpenWriteHandle(VendorPath, nullptr);
|
||||
p_Port->VendorWriteOutputLength = VendorOutputLength;
|
||||
|
||||
p_Port->HandleWriteVendor = Dri_Vendor_Func_OpenWriteHandle(VendorPath, nullptr);
|
||||
QString CommandPath;
|
||||
quint16 CommandOutputLength = 0;
|
||||
Mid_Struct_DeviceMatch CommandMatch;
|
||||
CommandMatch.VendorId = DeviceConfig.VendorId;
|
||||
CommandMatch.ProductId = DeviceConfig.ProductId;
|
||||
CommandMatch.UsagePage = MID_CONST_USAGE_PAGE_VENDOR_COMMAND;
|
||||
CommandMatch.Usage = MID_CONST_USAGE_VENDOR_COMMAND;
|
||||
if (Mid_FindHidInterface(
|
||||
CommandMatch,
|
||||
&CommandPath,
|
||||
nullptr,
|
||||
&CommandOutputLength))
|
||||
{
|
||||
QString TextError;
|
||||
p_Port->HandleWriteCommand = Dri_Hid_OpenWriteHandle(CommandPath, &TextError);
|
||||
p_Port->CommandWriteOutputLength = CommandOutputLength;
|
||||
if ((p_Port->HandleWriteCommand == INVALID_HANDLE_VALUE) && (p_TextStatus != nullptr))
|
||||
{
|
||||
*p_TextStatus = QStringLiteral("Vendor command write handle failed: %1").arg(TextError);
|
||||
}
|
||||
}
|
||||
else if (p_TextStatus != nullptr)
|
||||
{
|
||||
*p_TextStatus = QStringLiteral("Vendor command interface was not found: FF01 / 0005.");
|
||||
}
|
||||
|
||||
QString NkroPath;
|
||||
quint16 NkroOutputLength = 0;
|
||||
if (Mid_Func_FindHidInterface(
|
||||
Mid_Func_GetNkroMatch(DeviceConfig),
|
||||
Mid_Struct_DeviceMatch NkroMatch;
|
||||
NkroMatch.VendorId = DeviceConfig.VendorId;
|
||||
NkroMatch.ProductId = DeviceConfig.ProductId;
|
||||
NkroMatch.UsagePage = MID_CONST_USAGE_PAGE_NKRO;
|
||||
NkroMatch.Usage = MID_CONST_USAGE_NKRO;
|
||||
if (Mid_FindHidInterface(
|
||||
NkroMatch,
|
||||
&NkroPath,
|
||||
nullptr,
|
||||
&NkroOutputLength))
|
||||
{
|
||||
QString TextError;
|
||||
p_Port->HandleWriteNkro = Dri_Vendor_Func_OpenWriteHandle(NkroPath, &TextError);
|
||||
p_Port->HandleWriteNkro = Dri_Hid_OpenWriteHandle(NkroPath, &TextError);
|
||||
p_Port->NkroWriteOutputLength = NkroOutputLength;
|
||||
|
||||
if (p_Port->HandleWriteNkro == INVALID_HANDLE_VALUE)
|
||||
if ((p_Port->HandleWriteNkro == INVALID_HANDLE_VALUE) && (p_TextStatus != nullptr))
|
||||
{
|
||||
Dri_Vendor_Func_SetStatus(
|
||||
p_TextStatus,
|
||||
QStringLiteral("Vendor 读链路已打开,但 NKRO 写句柄打开失败:%1").arg(TextError));
|
||||
*p_TextStatus = QStringLiteral("NKRO write handle failed: %1").arg(TextError);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (p_TextStatus != nullptr)
|
||||
{
|
||||
Dri_Vendor_Func_SetStatus(
|
||||
p_TextStatus,
|
||||
QStringLiteral("Vendor 读链路已打开,但没有找到 NKRO 写接口。"));
|
||||
*p_TextStatus = QStringLiteral("NKRO write interface was not found.");
|
||||
}
|
||||
|
||||
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(
|
||||
bool Dri_Vendor_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;
|
||||
return Dri_Hid_Read(&p_Port->ReadPort, p_Packet, p_TextStatus);
|
||||
}
|
||||
|
||||
bool Dri_Vendor_Func_Write(
|
||||
bool Dri_Vendor_Write(
|
||||
Dri_Vendor_Struct_Port* p_Port,
|
||||
const QByteArray& ByteArray,
|
||||
QString* p_TextStatus)
|
||||
{
|
||||
if (!p_Port->IsOpened)
|
||||
const QString RouteLabel = p_Port->IsBluetoothTransport
|
||||
? QStringLiteral("Bluetooth Vendor")
|
||||
: QStringLiteral("Vendor");
|
||||
|
||||
if (!p_Port->ReadPort.IsOpened)
|
||||
{
|
||||
Dri_Vendor_Func_SetStatus(
|
||||
p_TextStatus,
|
||||
QStringLiteral("Vendor 读链路未打开,不能发送掩码。"));
|
||||
if (p_TextStatus != nullptr)
|
||||
{
|
||||
*p_TextStatus = QStringLiteral("%1 read path is not open, packet was not sent.").arg(RouteLabel);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (ByteArray.isEmpty())
|
||||
{
|
||||
if (p_TextStatus != nullptr)
|
||||
{
|
||||
*p_TextStatus = QStringLiteral("%1 packet is empty.").arg(RouteLabel);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList Errors;
|
||||
const auto TryWriteTo = [&](HANDLE HandleWrite,
|
||||
quint16 OutputLength,
|
||||
const QString& SuccessText,
|
||||
const QString& ErrorPrefix)
|
||||
QStringList ErrorList;
|
||||
const quint8 ReportId = static_cast<quint8>(ByteArray.at(0));
|
||||
|
||||
if (ReportId == Mid_Enum_ReportId_VendorCommand)
|
||||
{
|
||||
QString TextError;
|
||||
if (Dri_Vendor_Func_TryWritePacket(HandleWrite, OutputLength, ByteArray, &TextError))
|
||||
if (Dri_Vendor_TryWrite(
|
||||
p_Port->HandleWriteCommand,
|
||||
p_Port->CommandWriteOutputLength,
|
||||
ByteArray,
|
||||
QStringLiteral("Packet sent to %1 command interface.").arg(RouteLabel),
|
||||
RouteLabel + QStringLiteral(" command write failed: %1"),
|
||||
p_TextStatus,
|
||||
&ErrorList))
|
||||
{
|
||||
Dri_Vendor_Func_SetStatus(p_TextStatus, SuccessText);
|
||||
return true;
|
||||
}
|
||||
if (!TextError.isEmpty())
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Dri_Vendor_TryWrite(
|
||||
p_Port->HandleWriteNkro,
|
||||
p_Port->NkroWriteOutputLength,
|
||||
ByteArray,
|
||||
QStringLiteral("Packet sent to NKRO write interface."),
|
||||
QStringLiteral("NKRO write failed: %1"),
|
||||
p_TextStatus,
|
||||
&ErrorList))
|
||||
{
|
||||
Errors.append(ErrorPrefix.arg(TextError));
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
if (Dri_Vendor_TryWrite(
|
||||
p_Port->HandleWriteVendor,
|
||||
p_Port->VendorWriteOutputLength,
|
||||
ByteArray,
|
||||
QStringLiteral("Packet sent to %1 write interface.").arg(RouteLabel),
|
||||
RouteLabel + QStringLiteral(" write failed: %1"),
|
||||
p_TextStatus,
|
||||
&ErrorList))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Dri_Vendor_Func_SetStatus(
|
||||
p_TextStatus,
|
||||
Errors.isEmpty()
|
||||
? QStringLiteral("没有可用的写句柄,掩码发送未执行。")
|
||||
: Errors.join(QStringLiteral("\n")));
|
||||
if (p_TextStatus != nullptr)
|
||||
{
|
||||
*p_TextStatus = ErrorList.isEmpty()
|
||||
? QStringLiteral("No writable output handle is available, packet send was skipped.")
|
||||
: ErrorList.join(QStringLiteral("\n"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user