blob: 20a5d40012c11bc1240ff0a84ddb79495f0e5eb3 [file] [log] [blame]
// 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/dualshock4_controller_win.h"
#include <Unknwn.h>
#include <WinDef.h>
#include <stdint.h>
#include <windows.h>
namespace device {
Dualshock4ControllerWin::Dualshock4ControllerWin(HANDLE device_handle) {
UINT size;
UINT result =
::GetRawInputDeviceInfo(device_handle, RIDI_DEVICENAME, nullptr, &size);
if (result == 0U) {
std::unique_ptr<wchar_t[]> name_buffer(new wchar_t[size]);
result = ::GetRawInputDeviceInfo(device_handle, 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));
}
}
}
Dualshock4ControllerWin::~Dualshock4ControllerWin() = default;
void Dualshock4ControllerWin::DoShutdown() {
hid_handle_.Close();
}
size_t Dualshock4ControllerWin::WriteOutputReport(void* report,
size_t report_length) {
DCHECK(report);
DCHECK_GE(report_length, 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, report_length,
&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