#include "DRI/Dri_Hid.h" #include #pragma comment(lib, "hid.lib") namespace { bool Dri_Hid_BeginRead(Dri_Hid_Struct_ReadPort* 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; } if (p_TextStatus != nullptr) *p_TextStatus = QStringLiteral("%1 failed to start async read: %2").arg(p_Port->PortName).arg(GetLastError()); return false; } } // namespace void Dri_Hid_CloseReadPort(Dri_Hid_Struct_ReadPort* p_Port) { if ((p_Port->HandleRead != INVALID_HANDLE_VALUE) && p_Port->IsReadPending) CancelIoEx(p_Port->HandleRead, &p_Port->OverlappedRead); if (p_Port->HandleRead != INVALID_HANDLE_VALUE) CloseHandle(p_Port->HandleRead); if (p_Port->HandleEvent != nullptr) CloseHandle(p_Port->HandleEvent); *p_Port = Dri_Hid_Struct_ReadPort(); } bool Dri_Hid_InitReadPort( Dri_Hid_Struct_ReadPort* p_Port, const QString& DevicePath, quint16 InputLength, Mid_Enum_RawPacketSource PacketSource, const QString& PortName, QString* p_TextStatus) { Dri_Hid_CloseReadPort(p_Port); p_Port->HandleRead = CreateFileW( reinterpret_cast(DevicePath.utf16()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); if (p_Port->HandleRead == INVALID_HANDLE_VALUE) { if (p_TextStatus != nullptr) *p_TextStatus = QStringLiteral("%1 failed to open read handle: %2").arg(PortName).arg(GetLastError()); return false; } p_Port->HandleEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); if (p_Port->HandleEvent == nullptr) { if (p_TextStatus != nullptr) *p_TextStatus = QStringLiteral("%1 failed to create event: %2").arg(PortName).arg(GetLastError()); Dri_Hid_CloseReadPort(p_Port); return false; } p_Port->InputLength = InputLength; p_Port->PacketSource = PacketSource; p_Port->PortName = PortName; p_Port->ReadBuffer = QByteArray(InputLength, 0); p_Port->OverlappedRead.hEvent = p_Port->HandleEvent; p_Port->IsOpened = true; if (!Dri_Hid_BeginRead(p_Port, p_TextStatus)) { Dri_Hid_CloseReadPort(p_Port); return false; } return true; } bool Dri_Hid_Read( Dri_Hid_Struct_ReadPort* p_Port, Mid_Struct_RawPacket* p_Packet, QString* p_TextStatus) { *p_Packet = Mid_Struct_RawPacket(); p_Packet->Source = p_Port->PacketSource; p_Packet->PortName = p_Port->PortName; if (!p_Port->IsOpened) return false; if (!p_Port->IsReadPending) { Dri_Hid_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; if (p_TextStatus != nullptr) *p_TextStatus = QStringLiteral("%1 read packet failed: %2").arg(p_Port->PortName).arg(ErrorCode); Dri_Hid_CloseReadPort(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_Hid_BeginRead(p_Port, p_TextStatus); return p_Packet->IsValid; } HANDLE Dri_Hid_OpenWriteHandle(const QString& DevicePath, QString* p_TextError) { HANDLE HandleWrite = CreateFileW( reinterpret_cast(DevicePath.utf16()), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (HandleWrite != INVALID_HANDLE_VALUE) return HandleWrite; const DWORD WriteError = GetLastError(); HandleWrite = CreateFileW( reinterpret_cast(DevicePath.utf16()), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if ((HandleWrite == INVALID_HANDLE_VALUE) && (p_TextError != nullptr)) *p_TextError = QStringLiteral("GENERIC_WRITE=%1, ZeroAccess=%2").arg(WriteError).arg(GetLastError()); return HandleWrite; } bool Dri_Hid_WritePacket( HANDLE HandleWrite, quint16 OutputLength, const QByteArray& Packet, QString* p_TextError) { if ((HandleWrite == INVALID_HANDLE_VALUE) || Packet.isEmpty()) return false; QByteArray Buffer = Packet; 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; const DWORD WriteFileError = GetLastError(); 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 PaddedSetReportError = GetLastError(); BytesWritten = 0; if (WriteFile(HandleWrite, Buffer.constData(), static_cast(Buffer.size()), &BytesWritten, nullptr) && (BytesWritten == static_cast(Buffer.size()))) return true; const DWORD PaddedWriteFileError = GetLastError(); if (p_TextError != nullptr) { *p_TextError = QStringLiteral( "SetOutputReport=%1, WriteFile=%2, PaddedSetOutputReport=%3, PaddedWriteFile=%4") .arg(SetReportError) .arg(WriteFileError) .arg(PaddedSetReportError) .arg(PaddedWriteFileError); } return false; } if (p_TextError != nullptr) *p_TextError = QStringLiteral("SetOutputReport=%1, WriteFile=%2").arg(SetReportError).arg(WriteFileError); return false; }