Skip to content

Commit

Permalink
hidapi/windows: fixed PS4 controllers over Bluetooth on Windows 7
Browse files Browse the repository at this point in the history
Signed-off-by: Sam Lantinga <[email protected]>
  • Loading branch information
slouken committed May 26, 2023
1 parent d3013f0 commit 4f7de87
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
41 changes: 41 additions & 0 deletions windows/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ static HidD_GetPreparsedData_ HidD_GetPreparsedData;
static HidD_FreePreparsedData_ HidD_FreePreparsedData;
static HidP_GetCaps_ HidP_GetCaps;
static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
static HidD_SetOutputReport_ HidD_SetOutputReport;

static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL;
static CM_Get_Parent_ CM_Get_Parent = NULL;
Expand Down Expand Up @@ -147,6 +148,7 @@ static int lookup_functions()
RESOLVE(hid_lib_handle, HidD_FreePreparsedData);
RESOLVE(hid_lib_handle, HidP_GetCaps);
RESOLVE(hid_lib_handle, HidD_SetNumInputBuffers);
RESOLVE(hid_lib_handle, HidD_SetOutputReport);

RESOLVE(cfgmgr32_lib_handle, CM_Locate_DevNodeW);
RESOLVE(cfgmgr32_lib_handle, CM_Get_Parent);
Expand Down Expand Up @@ -183,8 +185,28 @@ struct hid_device_ {
OVERLAPPED ol;
OVERLAPPED write_ol;
struct hid_device_info* device_info;
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 );

memset(&osvi, 0, sizeof(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));
Expand Down Expand Up @@ -992,6 +1014,11 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
dev->read_buf = (char*) malloc(dev->input_report_length);
dev->device_info = hid_internal_get_device_info(interface_path, dev->device_handle);

/* 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 );
}

end_of_function:
free(interface_path);
CloseHandle(device_handle);
Expand All @@ -1003,6 +1030,16 @@ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
return dev;
}

static int hid_write_output_report(hid_device *dev, const unsigned char *data, size_t length)
{
BOOL res;
res = HidD_SetOutputReport(dev->device_handle, (void *)data, (ULONG)length);
if (res)
return (int)length;
else
return -1;
}

int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
{
DWORD bytes_written = 0;
Expand All @@ -1019,6 +1056,10 @@ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *

register_string_error(dev, NULL);

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
Expand Down
1 change: 1 addition & 0 deletions windows/hidapi_hidsdi.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_
typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
typedef BOOLEAN (__stdcall *HidD_SetOutputReport_)(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength);

#endif

Expand Down

0 comments on commit 4f7de87

Please sign in to comment.