Skip to content

Commit 4cd8137

Browse files
committed
hidapi/windows: fixed PS4 controllers over Bluetooth on Windows 7
Signed-off-by: Sam Lantinga <[email protected]>
1 parent c19ae12 commit 4cd8137

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

windows/hid.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ static HidD_GetPreparsedData_ HidD_GetPreparsedData;
9494
static HidD_FreePreparsedData_ HidD_FreePreparsedData;
9595
static HidP_GetCaps_ HidP_GetCaps;
9696
static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
97+
static HidD_SetOutputReport_ HidD_SetOutputReport;
9798

9899
static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL;
99100
static CM_Get_Parent_ CM_Get_Parent = NULL;
@@ -147,6 +148,7 @@ static int lookup_functions()
147148
RESOLVE(hid_lib_handle, HidD_FreePreparsedData);
148149
RESOLVE(hid_lib_handle, HidP_GetCaps);
149150
RESOLVE(hid_lib_handle, HidD_SetNumInputBuffers);
151+
RESOLVE(hid_lib_handle, HidD_SetOutputReport);
150152

151153
RESOLVE(cfgmgr32_lib_handle, CM_Locate_DevNodeW);
152154
RESOLVE(cfgmgr32_lib_handle, CM_Get_Parent);
@@ -183,8 +185,28 @@ struct hid_device_ {
183185
OVERLAPPED ol;
184186
OVERLAPPED write_ol;
185187
struct hid_device_info* device_info;
188+
BOOL use_hid_write_output_report;
186189
};
187190

191+
static BOOL hid_internal_is_windows_version_or_greater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
192+
{
193+
OSVERSIONINFOEXW osvi;
194+
DWORDLONG const dwlConditionMask = VerSetConditionMask(
195+
VerSetConditionMask(
196+
VerSetConditionMask(
197+
0, VER_MAJORVERSION, VER_GREATER_EQUAL ),
198+
VER_MINORVERSION, VER_GREATER_EQUAL ),
199+
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
200+
201+
memset(&osvi, 0, sizeof(osvi));
202+
osvi.dwOSVersionInfoSize = sizeof( osvi );
203+
osvi.dwMajorVersion = wMajorVersion;
204+
osvi.dwMinorVersion = wMinorVersion;
205+
osvi.wServicePackMajor = wServicePackMajor;
206+
207+
return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
208+
}
209+
188210
static hid_device *new_hid_device()
189211
{
190212
hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
@@ -992,6 +1014,11 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
9921014
dev->read_buf = (char*) malloc(dev->input_report_length);
9931015
dev->device_info = hid_internal_get_device_info(interface_path, dev->device_handle);
9941016

1017+
/* On Windows 7, we need to use hid_write_output_report() over Bluetooth */
1018+
if (dev->output_report_length > 512) {
1019+
dev->use_hid_write_output_report = !hid_internal_is_windows_version_or_greater( HIBYTE( _WIN32_WINNT_WIN8 ), LOBYTE( _WIN32_WINNT_WIN8 ), 0 );
1020+
}
1021+
9951022
end_of_function:
9961023
free(interface_path);
9971024
CloseHandle(device_handle);
@@ -1003,6 +1030,16 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
10031030
return dev;
10041031
}
10051032

1033+
static int hid_internal_write_output_report(hid_device *dev, const unsigned char *data, size_t length)
1034+
{
1035+
BOOL res;
1036+
res = HidD_SetOutputReport(dev->device_handle, (void *)data, (ULONG)length);
1037+
if (res)
1038+
return (int)length;
1039+
else
1040+
return -1;
1041+
}
1042+
10061043
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
10071044
{
10081045
DWORD bytes_written = 0;
@@ -1019,6 +1056,10 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *
10191056

10201057
register_string_error(dev, NULL);
10211058

1059+
if (dev->use_hid_write_output_report) {
1060+
return hid_internal_write_output_report(dev, data, length);
1061+
}
1062+
10221063
/* Make sure the right number of bytes are passed to WriteFile. Windows
10231064
expects the number of bytes which are in the _longest_ report (plus
10241065
one for the report number) bytes even if the data is a report

windows/hidapi_hidsdi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_
5454
typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
5555
typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
5656
typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
57+
typedef BOOLEAN (__stdcall *HidD_SetOutputReport_)(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength);
5758

5859
#endif
5960

0 commit comments

Comments
 (0)