summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Lantinga <slouken@libsdl.org>2021-01-27 21:30:17 -0800
committerSam Lantinga <slouken@libsdl.org>2021-01-27 21:30:17 -0800
commit3315ed436aa27d83eea614376d8a16869adea9eb (patch)
tree60f0f34fd5ebefd0d177b7ee23bc1e67ecedde7a
parent8107293da0a13ff4de22234d5df23d317630e828 (diff)
downloadsdl-3315ed436aa27d83eea614376d8a16869adea9eb.tar.gz
Fixed PS4 controllers over Bluetooth on Windows 7
-rw-r--r--src/hidapi/windows/hid.c95
1 files changed, 57 insertions, 38 deletions
diff --git a/src/hidapi/windows/hid.c b/src/hidapi/windows/hid.c
index 92dd6a72d..424cbe9f0 100644
--- a/src/hidapi/windows/hid.c
+++ b/src/hidapi/windows/hid.c
@@ -25,6 +25,10 @@
#include <windows.h>
+#ifndef _WIN32_WINNT_WIN8
+#define _WIN32_WINNT_WIN8 0x0602
+#endif
+
#if 0 /* can cause redefinition errors on some toolchains */
#ifdef __MINGW32__
#include <ntdef.h>
@@ -176,8 +180,29 @@ struct hid_device_ {
char *read_buf;
OVERLAPPED ol;
OVERLAPPED write_ol;
+ BOOL use_hid_write_output_report;
};
+static BOOL
+IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
+{
+ OSVERSIONINFOEXW osvi;
+ DWORDLONG const dwlConditionMask = VerSetConditionMask(
+ VerSetConditionMask(
+ VerSetConditionMask(
+ 0, VER_MAJORVERSION, VER_GREATER_EQUAL ),
+ VER_MINORVERSION, VER_GREATER_EQUAL ),
+ VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
+
+ SDL_zero( osvi );
+ osvi.dwOSVersionInfoSize = sizeof( osvi );
+ osvi.dwMajorVersion = wMajorVersion;
+ osvi.dwMinorVersion = wMinorVersion;
+ osvi.wServicePackMajor = wServicePackMajor;
+
+ return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
+}
+
static hid_device *new_hid_device()
{
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
@@ -693,6 +718,11 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bEx
dev->input_report_length = caps.InputReportByteLength;
HidD_FreePreparsedData(pp_data);
+ /* On Windows 7, we need to use hid_write_output_report() over Bluetooth */
+ if (dev->output_report_length > 512) {
+ dev->use_hid_write_output_report = !IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN8 ), LOBYTE( _WIN32_WINNT_WIN8 ), 0 );
+ }
+
dev->read_buf = (char*) malloc(dev->input_report_length);
return dev;
@@ -721,14 +751,10 @@ static int hid_write_timeout(hid_device *dev, const unsigned char *data, size_t
size_t stashed_length = length;
unsigned char *buf;
-#if 1
- /* If the application is writing to the device, it knows how much data to write.
- * This matches the behavior on other platforms. It's also important when writing
- * to Sony game controllers over Bluetooth, where there's a CRC at the end which
- * must not be tampered with.
- */
- buf = (unsigned char *) data;
-#else
+ if (dev->use_hid_write_output_report) {
+ return hid_write_output_report(dev, data, length);
+ }
+
/* Make sure the right number of bytes are passed to WriteFile. Windows
expects the number of bytes which are in the _longest_ report (plus
one for the report number) bytes even if the data is a report
@@ -746,42 +772,35 @@ static int hid_write_timeout(hid_device *dev, const unsigned char *data, size_t
memset(buf + length, 0, dev->output_report_length - length);
length = dev->output_report_length;
}
-#endif
- if (length > 512)
- {
- return hid_write_output_report( dev, data, stashed_length );
- }
- else
- {
- res = WriteFile( dev->device_handle, buf, ( DWORD ) length, NULL, &dev->write_ol );
- if (!res) {
- if (GetLastError() != ERROR_IO_PENDING) {
- /* WriteFile() failed. Return error. */
- register_error(dev, "WriteFile");
- bytes_written = (DWORD) -1;
- goto end_of_function;
- }
- }
- /* Wait here until the write is done. This makes
- hid_write() synchronous. */
- res = WaitForSingleObject(dev->write_ol.hEvent, milliseconds);
- if (res != WAIT_OBJECT_0)
- {
- // There was a Timeout.
- bytes_written = (DWORD) -1;
- register_error(dev, "WriteFile/WaitForSingleObject Timeout");
- goto end_of_function;
- }
-
- res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*F=don't_wait*/);
- if (!res) {
- /* The Write operation failed. */
+ res = WriteFile( dev->device_handle, buf, ( DWORD ) length, NULL, &dev->write_ol );
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* WriteFile() failed. Return error. */
register_error(dev, "WriteFile");
bytes_written = (DWORD) -1;
goto end_of_function;
}
}
+
+ /* Wait here until the write is done. This makes hid_write() synchronous. */
+ res = WaitForSingleObject(dev->write_ol.hEvent, milliseconds);
+ if (res != WAIT_OBJECT_0)
+ {
+ // There was a Timeout.
+ bytes_written = (DWORD) -1;
+ register_error(dev, "WriteFile/WaitForSingleObject Timeout");
+ goto end_of_function;
+ }
+
+ res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*F=don't_wait*/);
+ if (!res) {
+ /* The Write operation failed. */
+ register_error(dev, "WriteFile");
+ bytes_written = (DWORD) -1;
+ goto end_of_function;
+ }
+
end_of_function:
if (buf != data)
free(buf);