Commit 9dc1ddf8 authored by Tyson Whitehead's avatar Tyson Whitehead Committed by Alexandre Julliard

dinput: Implement DIPROP_AUTOCENTER.

Autocenter is a default effect playing on the device following power up or reset. It is disabled by stopping all effects. On at least some devices (all?) it is a spring effect playing in slot 1. Capturing Windows USB packets reveals it dinput acquire does (1) a reset (this enabled autocenter) and, if autocenter is disabled, (2) a stop all effects (this disabled autocenter). This logic works regardless of whether autocenter is a spring effect playing in slot 1 or not. It does mean autocenter can only be set when the device is not acquired. Testing on Windows reveals setting autocenter properties while acquired returns DIERR_ACQUIRED even if the device is exclusively acquired, so this is consistent.
parent 63562c05
...@@ -899,7 +899,7 @@ static HRESULT check_property( struct dinput_device *impl, const GUID *guid, con ...@@ -899,7 +899,7 @@ static HRESULT check_property( struct dinput_device *impl, const GUID *guid, con
switch (LOWORD( guid )) switch (LOWORD( guid ))
{ {
case (DWORD_PTR)DIPROP_AUTOCENTER: case (DWORD_PTR)DIPROP_AUTOCENTER:
if (impl->status == STATUS_ACQUIRED && !is_exclusively_acquired( impl )) return DIERR_ACQUIRED; if (impl->status == STATUS_ACQUIRED) return DIERR_ACQUIRED;
break; break;
case (DWORD_PTR)DIPROP_AXISMODE: case (DWORD_PTR)DIPROP_AXISMODE:
case (DWORD_PTR)DIPROP_BUFFERSIZE: case (DWORD_PTR)DIPROP_BUFFERSIZE:
...@@ -1290,8 +1290,6 @@ static HRESULT dinput_device_set_property( IDirectInputDevice8W *iface, const GU ...@@ -1290,8 +1290,6 @@ static HRESULT dinput_device_set_property( IDirectInputDevice8W *iface, const GU
{ {
const DIPROPDWORD *value = (const DIPROPDWORD *)header; const DIPROPDWORD *value = (const DIPROPDWORD *)header;
if (!(impl->caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED; if (!(impl->caps.dwFlags & DIDC_FORCEFEEDBACK)) return DIERR_UNSUPPORTED;
FIXME( "DIPROP_AUTOCENTER stub!\n" );
impl->autocenter = value->dwData; impl->autocenter = value->dwData;
return DI_OK; return DI_OK;
} }
...@@ -2131,6 +2129,7 @@ void dinput_device_init( struct dinput_device *device, const struct dinput_devic ...@@ -2131,6 +2129,7 @@ void dinput_device_init( struct dinput_device *device, const struct dinput_devic
device->caps.dwSize = sizeof(DIDEVCAPS); device->caps.dwSize = sizeof(DIDEVCAPS);
device->caps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED; device->caps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED;
device->device_gain = 10000; device->device_gain = 10000;
device->autocenter = DIPROPAUTOCENTER_ON;
device->force_feedback_state = DIGFFS_STOPPED | DIGFFS_EMPTY; device->force_feedback_state = DIGFFS_STOPPED | DIGFFS_EMPTY;
InitializeCriticalSection( &device->crit ); InitializeCriticalSection( &device->crit );
dinput_internal_addref( (device->dinput = dinput) ); dinput_internal_addref( (device->dinput = dinput) );
......
...@@ -1072,7 +1072,12 @@ static HRESULT hid_joystick_send_force_feedback_command( IDirectInputDevice8W *i ...@@ -1072,7 +1072,12 @@ static HRESULT hid_joystick_send_force_feedback_command( IDirectInputDevice8W *i
if (status != HIDP_STATUS_SUCCESS) return status; if (status != HIDP_STATUS_SUCCESS) return status;
if (!WriteFile( impl->device, report_buf, report_len, NULL, NULL )) return DIERR_INPUTLOST; if (!WriteFile( impl->device, report_buf, report_len, NULL, NULL )) return DIERR_INPUTLOST;
if (!unacquire && command == DISFFC_RESET) hid_joystick_send_device_gain( iface, impl->base.device_gain ); if (!unacquire && command == DISFFC_RESET)
{
if (impl->base.autocenter == DIPROPAUTOCENTER_OFF)
hid_joystick_send_force_feedback_command( iface, DISFFC_STOPALL, FALSE );
hid_joystick_send_device_gain( iface, impl->base.device_gain );
}
return DI_OK; return DI_OK;
} }
......
...@@ -2222,7 +2222,6 @@ static BOOL test_force_feedback_joystick( DWORD version ) ...@@ -2222,7 +2222,6 @@ static BOOL test_force_feedback_joystick( DWORD version )
.report_len = 2, .report_len = 2,
.report_buf = {1, 0x02}, .report_buf = {1, 0x02},
.broken_id = 8, /* Win8 sends them in the reverse order */ .broken_id = 8, /* Win8 sends them in the reverse order */
.todo = TRUE,
}, },
{ {
.code = IOCTL_HID_WRITE_REPORT, .code = IOCTL_HID_WRITE_REPORT,
......
...@@ -105,6 +105,7 @@ MAKE_FUNCPTR(SDL_HapticRumbleStop); ...@@ -105,6 +105,7 @@ MAKE_FUNCPTR(SDL_HapticRumbleStop);
MAKE_FUNCPTR(SDL_HapticRumbleSupported); MAKE_FUNCPTR(SDL_HapticRumbleSupported);
MAKE_FUNCPTR(SDL_HapticRunEffect); MAKE_FUNCPTR(SDL_HapticRunEffect);
MAKE_FUNCPTR(SDL_HapticSetGain); MAKE_FUNCPTR(SDL_HapticSetGain);
MAKE_FUNCPTR(SDL_HapticSetAutocenter);
MAKE_FUNCPTR(SDL_HapticStopAll); MAKE_FUNCPTR(SDL_HapticStopAll);
MAKE_FUNCPTR(SDL_HapticStopEffect); MAKE_FUNCPTR(SDL_HapticStopEffect);
MAKE_FUNCPTR(SDL_HapticUnpause); MAKE_FUNCPTR(SDL_HapticUnpause);
...@@ -550,6 +551,7 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US ...@@ -550,6 +551,7 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US
return STATUS_SUCCESS; return STATUS_SUCCESS;
case PID_USAGE_DC_STOP_ALL_EFFECTS: case PID_USAGE_DC_STOP_ALL_EFFECTS:
pSDL_HapticStopAll(impl->sdl_haptic); pSDL_HapticStopAll(impl->sdl_haptic);
pSDL_HapticSetAutocenter(impl->sdl_haptic, 0);
return STATUS_SUCCESS; return STATUS_SUCCESS;
case PID_USAGE_DC_DEVICE_RESET: case PID_USAGE_DC_DEVICE_RESET:
pSDL_HapticStopAll(impl->sdl_haptic); pSDL_HapticStopAll(impl->sdl_haptic);
...@@ -559,6 +561,7 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US ...@@ -559,6 +561,7 @@ static NTSTATUS sdl_device_physical_device_control(struct unix_device *iface, US
pSDL_HapticDestroyEffect(impl->sdl_haptic, impl->effect_ids[i]); pSDL_HapticDestroyEffect(impl->sdl_haptic, impl->effect_ids[i]);
impl->effect_ids[i] = -1; impl->effect_ids[i] = -1;
} }
pSDL_HapticSetAutocenter(impl->sdl_haptic, 100);
return STATUS_SUCCESS; return STATUS_SUCCESS;
case PID_USAGE_DC_DEVICE_PAUSE: case PID_USAGE_DC_DEVICE_PAUSE:
pSDL_HapticPause(impl->sdl_haptic); pSDL_HapticPause(impl->sdl_haptic);
...@@ -1121,6 +1124,7 @@ NTSTATUS sdl_bus_init(void *args) ...@@ -1121,6 +1124,7 @@ NTSTATUS sdl_bus_init(void *args)
LOAD_FUNCPTR(SDL_HapticRumbleSupported); LOAD_FUNCPTR(SDL_HapticRumbleSupported);
LOAD_FUNCPTR(SDL_HapticRunEffect); LOAD_FUNCPTR(SDL_HapticRunEffect);
LOAD_FUNCPTR(SDL_HapticSetGain); LOAD_FUNCPTR(SDL_HapticSetGain);
LOAD_FUNCPTR(SDL_HapticSetAutocenter);
LOAD_FUNCPTR(SDL_HapticStopAll); LOAD_FUNCPTR(SDL_HapticStopAll);
LOAD_FUNCPTR(SDL_HapticStopEffect); LOAD_FUNCPTR(SDL_HapticStopEffect);
LOAD_FUNCPTR(SDL_HapticUnpause); LOAD_FUNCPTR(SDL_HapticUnpause);
......
...@@ -929,6 +929,24 @@ static NTSTATUS lnxev_device_physical_effect_run(struct lnxev_device *impl, BYTE ...@@ -929,6 +929,24 @@ static NTSTATUS lnxev_device_physical_effect_run(struct lnxev_device *impl, BYTE
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static NTSTATUS lnxev_device_physical_device_set_autocenter(struct unix_device *iface, BYTE percent)
{
struct lnxev_device *impl = lnxev_impl_from_unix_device(iface);
struct input_event ie =
{
.type = EV_FF,
.code = FF_AUTOCENTER,
.value = 0xffff * percent / 100,
};
TRACE("iface %p, percent %#x.\n", iface, percent);
if (write(impl->base.device_fd, &ie, sizeof(ie)) == -1)
WARN("write failed %d %s\n", errno, strerror(errno));
return STATUS_SUCCESS;
}
static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, USAGE control) static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, USAGE control)
{ {
struct lnxev_device *impl = lnxev_impl_from_unix_device(iface); struct lnxev_device *impl = lnxev_impl_from_unix_device(iface);
...@@ -972,6 +990,7 @@ static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, ...@@ -972,6 +990,7 @@ static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface,
if (impl->effect_ids[i] < 0) continue; if (impl->effect_ids[i] < 0) continue;
lnxev_device_physical_effect_run(impl, i, 0); lnxev_device_physical_effect_run(impl, i, 0);
} }
lnxev_device_physical_device_set_autocenter(iface, 0);
return STATUS_SUCCESS; return STATUS_SUCCESS;
case PID_USAGE_DC_DEVICE_RESET: case PID_USAGE_DC_DEVICE_RESET:
for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i) for (i = 0; i < ARRAY_SIZE(impl->effect_ids); ++i)
...@@ -981,6 +1000,7 @@ static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface, ...@@ -981,6 +1000,7 @@ static NTSTATUS lnxev_device_physical_device_control(struct unix_device *iface,
WARN("couldn't free effect, EVIOCRMFF ioctl failed: %d %s\n", errno, strerror(errno)); WARN("couldn't free effect, EVIOCRMFF ioctl failed: %d %s\n", errno, strerror(errno));
impl->effect_ids[i] = -1; impl->effect_ids[i] = -1;
} }
lnxev_device_physical_device_set_autocenter(iface, 100);
return STATUS_SUCCESS; return STATUS_SUCCESS;
case PID_USAGE_DC_DEVICE_PAUSE: case PID_USAGE_DC_DEVICE_PAUSE:
WARN("device pause not supported\n"); WARN("device pause not supported\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment