winebus.sys: Implement SDL Haptic for controller vibration.

Signed-off-by: Aric Stewart <aric@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Aric Stewart 2018-02-21 06:57:18 -06:00 committed by Alexandre Julliard
parent 2505d67cbc
commit 249db7e49e
1 changed files with 131 additions and 3 deletions

View File

@ -110,6 +110,18 @@ MAKE_FUNCPTR(SDL_GameControllerGetAxis);
MAKE_FUNCPTR(SDL_GameControllerName);
MAKE_FUNCPTR(SDL_GameControllerOpen);
MAKE_FUNCPTR(SDL_GameControllerEventState);
MAKE_FUNCPTR(SDL_HapticClose);
MAKE_FUNCPTR(SDL_HapticDestroyEffect);
MAKE_FUNCPTR(SDL_HapticNewEffect);
MAKE_FUNCPTR(SDL_HapticOpenFromJoystick);
MAKE_FUNCPTR(SDL_HapticQuery);
MAKE_FUNCPTR(SDL_HapticRumbleInit);
MAKE_FUNCPTR(SDL_HapticRumblePlay);
MAKE_FUNCPTR(SDL_HapticRumbleSupported);
MAKE_FUNCPTR(SDL_HapticRunEffect);
MAKE_FUNCPTR(SDL_HapticStopAll);
MAKE_FUNCPTR(SDL_JoystickIsHaptic);
MAKE_FUNCPTR(SDL_memset);
#endif
static Uint16 (*pSDL_JoystickGetProduct)(SDL_Joystick * joystick);
static Uint16 (*pSDL_JoystickGetProductVersion)(SDL_Joystick * joystick);
@ -130,6 +142,9 @@ struct platform_private
int buffer_length;
BYTE *report_buffer;
SDL_Haptic *sdl_haptic;
int haptic_effect_id;
};
static inline struct platform_private *impl_from_DEVICE_OBJECT(DEVICE_OBJECT *device)
@ -193,6 +208,28 @@ static const BYTE CONTROLLER_TRIGGERS [] = {
0x81, 0x02, /* INPUT (Data,Var,Abs) */
};
static const BYTE HAPTIC_RUMBLE[] = {
0x06, 0x00, 0xff, /* USAGE PAGE (vendor-defined) */
0x09, 0x01, /* USAGE (1) */
0x85, 0x00, /* REPORT_ID (0) */
/* padding */
0x95, 0x02, /* REPORT_COUNT (2) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
/* actuators */
0x15, 0x00, /* LOGICAL MINIMUM (0) */
0x25, 0xff, /* LOGICAL MAXIMUM (255) */
0x35, 0x00, /* PHYSICAL MINIMUM (0) */
0x45, 0xff, /* PHYSICAL MAXIMUM (255) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x95, 0x02, /* REPORT_COUNT (2) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
/* padding */
0x95, 0x02, /* REPORT_COUNT (3) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
};
static BYTE *add_axis_block(BYTE *report_ptr, BYTE count, BYTE page, const BYTE *usages, BOOL absolute)
{
int i;
@ -257,6 +294,40 @@ static void set_hat_value(struct platform_private *ext, int index, int value)
}
}
static int test_haptic(struct platform_private *ext)
{
int rc = 0;
if (pSDL_JoystickIsHaptic(ext->sdl_joystick))
{
ext->sdl_haptic = pSDL_HapticOpenFromJoystick(ext->sdl_joystick);
if (ext->sdl_haptic &&
((pSDL_HapticQuery(ext->sdl_haptic) & SDL_HAPTIC_LEFTRIGHT) != 0 ||
pSDL_HapticRumbleSupported(ext->sdl_haptic)))
{
pSDL_HapticStopAll(ext->sdl_haptic);
pSDL_HapticRumbleInit(ext->sdl_haptic);
rc = sizeof(HAPTIC_RUMBLE);
ext->haptic_effect_id = -1;
}
else
{
pSDL_HapticClose(ext->sdl_haptic);
ext->sdl_haptic = NULL;
}
}
return rc;
}
static int build_haptic(struct platform_private *ext, BYTE *report_ptr)
{
if (ext->sdl_haptic)
{
memcpy(report_ptr, HAPTIC_RUMBLE, sizeof(HAPTIC_RUMBLE));
return (sizeof(HAPTIC_RUMBLE));
}
return 0;
}
static BOOL build_report_descriptor(struct platform_private *ext)
{
BYTE *report_ptr;
@ -338,6 +409,8 @@ static BOOL build_report_descriptor(struct platform_private *ext)
report_size++;
}
descript_size += test_haptic(ext);
TRACE("Report Descriptor will be %i bytes\n", descript_size);
TRACE("Report will be %i bytes\n", report_size);
@ -377,6 +450,7 @@ static BOOL build_report_descriptor(struct platform_private *ext)
if (hat_count)
report_ptr = add_hatswitch(report_ptr, hat_count);
report_ptr += build_haptic(ext, report_ptr);
memcpy(report_ptr, REPORT_TAIL, sizeof(REPORT_TAIL));
ext->report_descriptor_size = descript_size;
@ -407,6 +481,7 @@ static BOOL build_mapped_report_descriptor(struct platform_private *ext)
descript_size += sizeof(CONTROLLER_BUTTONS);
descript_size += sizeof(CONTROLLER_AXIS);
descript_size += sizeof(CONTROLLER_TRIGGERS);
descript_size += test_haptic(ext);
ext->axis_start = 2;
ext->buffer_length = 14;
@ -432,6 +507,7 @@ static BOOL build_mapped_report_descriptor(struct platform_private *ext)
report_ptr += sizeof(CONTROLLER_AXIS);
memcpy(report_ptr, CONTROLLER_TRIGGERS, sizeof(CONTROLLER_TRIGGERS));
report_ptr += sizeof(CONTROLLER_TRIGGERS);
report_ptr += build_haptic(ext, report_ptr);
memcpy(report_ptr, REPORT_TAIL, sizeof(REPORT_TAIL));
ext->report_descriptor_size = descript_size;
@ -509,8 +585,48 @@ static NTSTATUS begin_report_processing(DEVICE_OBJECT *device)
static NTSTATUS set_output_report(DEVICE_OBJECT *device, UCHAR id, BYTE *report, DWORD length, ULONG_PTR *written)
{
*written = 0;
return STATUS_NOT_IMPLEMENTED;
struct platform_private *ext = impl_from_DEVICE_OBJECT(device);
if (ext->sdl_haptic && id == 0)
{
WORD left = report[2] * 128;
WORD right = report[3] * 128;
if (ext->haptic_effect_id >= 0)
{
pSDL_HapticDestroyEffect(ext->sdl_haptic, ext->haptic_effect_id);
ext->haptic_effect_id = -1;
}
pSDL_HapticStopAll(ext->sdl_haptic);
if (left != 0 || right != 0)
{
SDL_HapticEffect effect;
pSDL_memset( &effect, 0, sizeof(SDL_HapticEffect) );
effect.type = SDL_HAPTIC_LEFTRIGHT;
effect.leftright.length = -1;
effect.leftright.large_magnitude = left;
effect.leftright.small_magnitude = right;
ext->haptic_effect_id = pSDL_HapticNewEffect(ext->sdl_haptic, &effect);
if (ext->haptic_effect_id >= 0)
{
pSDL_HapticRunEffect(ext->sdl_haptic, ext->haptic_effect_id, 1);
}
else
{
float i = (float)((left + right)/2.0) / 32767.0;
pSDL_HapticRumblePlay(ext->sdl_haptic, i, -1);
}
}
*written = length;
return STATUS_SUCCESS;
}
else
{
*written = 0;
return STATUS_NOT_IMPLEMENTED;
}
}
static NTSTATUS get_feature_report(DEVICE_OBJECT *device, UCHAR id, BYTE *report, DWORD length, ULONG_PTR *read)
@ -790,7 +906,7 @@ static DWORD CALLBACK deviceloop_thread(void *args)
HANDLE init_done = args;
SDL_Event event;
if (pSDL_Init(SDL_INIT_GAMECONTROLLER) < 0)
if (pSDL_Init(SDL_INIT_GAMECONTROLLER|SDL_INIT_HAPTIC) < 0)
{
ERR("Can't Init SDL\n");
return STATUS_UNSUCCESSFUL;
@ -847,6 +963,18 @@ NTSTATUS WINAPI sdl_driver_init(DRIVER_OBJECT *driver, UNICODE_STRING *registry_
LOAD_FUNCPTR(SDL_GameControllerName);
LOAD_FUNCPTR(SDL_GameControllerOpen);
LOAD_FUNCPTR(SDL_GameControllerEventState);
LOAD_FUNCPTR(SDL_HapticClose);
LOAD_FUNCPTR(SDL_HapticDestroyEffect);
LOAD_FUNCPTR(SDL_HapticNewEffect);
LOAD_FUNCPTR(SDL_HapticOpenFromJoystick);
LOAD_FUNCPTR(SDL_HapticQuery);
LOAD_FUNCPTR(SDL_HapticRumbleInit);
LOAD_FUNCPTR(SDL_HapticRumblePlay);
LOAD_FUNCPTR(SDL_HapticRumbleSupported);
LOAD_FUNCPTR(SDL_HapticRunEffect);
LOAD_FUNCPTR(SDL_HapticStopAll);
LOAD_FUNCPTR(SDL_JoystickIsHaptic);
LOAD_FUNCPTR(SDL_memset);
#undef LOAD_FUNCPTR
pSDL_JoystickGetProduct = wine_dlsym(sdl_handle, "SDL_JoystickGetProduct", NULL, 0);
pSDL_JoystickGetProductVersion = wine_dlsym(sdl_handle, "SDL_JoystickGetProductVersion", NULL, 0);