12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "device/gamepad/hid_writer_win.h"
- #include <Unknwn.h>
- #include <WinDef.h>
- #include <stdint.h>
- #include <windows.h>
- namespace device {
- HidWriterWin::HidWriterWin(HANDLE device) {
- UINT size;
- UINT result =
- ::GetRawInputDeviceInfo(device, RIDI_DEVICENAME, nullptr, &size);
- if (result == 0U) {
- std::unique_ptr<wchar_t[]> name_buffer(new wchar_t[size]);
- result = ::GetRawInputDeviceInfo(device, RIDI_DEVICENAME, name_buffer.get(),
- &size);
- if (result == size) {
- // Open the device handle for asynchronous I/O.
- hid_handle_.Set(
- ::CreateFile(name_buffer.get(), GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
- OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr));
- }
- }
- }
- HidWriterWin::~HidWriterWin() = default;
- size_t HidWriterWin::WriteOutputReport(base::span<const uint8_t> report) {
- DCHECK_GE(report.size_bytes(), 1U);
- if (!hid_handle_.IsValid())
- return 0;
- base::win::ScopedHandle event_handle(
- ::CreateEvent(nullptr, false, false, L""));
- OVERLAPPED overlapped = {0};
- overlapped.hEvent = event_handle.Get();
- // Set up an asynchronous write.
- DWORD bytes_written = 0;
- BOOL write_success =
- ::WriteFile(hid_handle_.Get(), report.data(), report.size_bytes(),
- &bytes_written, &overlapped);
- if (!write_success) {
- DWORD error = ::GetLastError();
- if (error == ERROR_IO_PENDING) {
- // Wait for the write to complete. This causes WriteOutputReport to behave
- // synchronously.
- DWORD wait_object = ::WaitForSingleObject(overlapped.hEvent, 100);
- if (wait_object == WAIT_OBJECT_0) {
- ::GetOverlappedResult(hid_handle_.Get(), &overlapped, &bytes_written,
- true);
- } else {
- // Wait failed, or the timeout was exceeded before the write completed.
- // Cancel the write request.
- if (::CancelIo(hid_handle_.Get())) {
- HANDLE handles[2];
- handles[0] = hid_handle_.Get();
- handles[1] = overlapped.hEvent;
- ::WaitForMultipleObjects(2, handles, false, INFINITE);
- }
- }
- }
- }
- return write_success ? bytes_written : 0;
- }
- } // namespace device
|