From: Rémi Bernon rbernon@codeweavers.com
--- dlls/joy.cpl/dinput.c | 514 +++++++++++++++++++++++++++++++++++-- dlls/joy.cpl/joy_private.h | 2 +- dlls/joy.cpl/main.c | 496 +---------------------------------- 3 files changed, 494 insertions(+), 518 deletions(-)
diff --git a/dlls/joy.cpl/dinput.c b/dlls/joy.cpl/dinput.c index bf80584000e..521634ff7da 100644 --- a/dlls/joy.cpl/dinput.c +++ b/dlls/joy.cpl/dinput.c @@ -35,6 +35,18 @@
WINE_DEFAULT_DEBUG_CHANNEL(joycpl);
+struct effect +{ + struct list entry; + IDirectInputEffect *effect; +}; + +struct device +{ + struct list entry; + IDirectInputDevice8W *device; +}; + static CRITICAL_SECTION state_cs; static CRITICAL_SECTION_DEBUG state_cs_debug = { @@ -44,31 +56,256 @@ static CRITICAL_SECTION_DEBUG state_cs_debug = }; static CRITICAL_SECTION state_cs = { &state_cs_debug, -1, 0, 0, 0, 0 };
-static DIJOYSTATE last_state; -static DIDEVCAPS last_caps; +static struct list effects = LIST_INIT( effects ); +static IDirectInputEffect *effect_selected;
-void set_di_device_state( HWND hwnd, DIJOYSTATE *state, DIDEVCAPS *caps ) +static struct list devices = LIST_INIT( devices ); +static IDirectInputDevice8W *device_selected; + +static HWND dialog_hwnd; +static HANDLE state_event; + +static BOOL CALLBACK enum_effects( const DIEFFECTINFOW *info, void *context ) { - BOOL modified; + IDirectInputDevice8W *device = context; + DWORD axes[2] = {DIJOFS_X, DIJOFS_Y}; + LONG direction[2] = {0}; + DIEFFECT params = + { + .dwSize = sizeof(DIEFFECT), + .dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS, + .dwDuration = 2 * DI_SECONDS, + .dwGain = DI_FFNOMINALMAX, + .rglDirection = direction, + .rgdwAxes = axes, + .cAxes = 2, + }; + DICONSTANTFORCE constant = + { + .lMagnitude = DI_FFNOMINALMAX, + }; + DIPERIODIC periodic = + { + .dwMagnitude = DI_FFNOMINALMAX, + .dwPeriod = DI_SECONDS / 2, + }; + DICONDITION condition = + { + .dwPositiveSaturation = 10000, + .dwNegativeSaturation = 10000, + .lPositiveCoefficient = 10000, + .lNegativeCoefficient = 10000, + }; + DIRAMPFORCE ramp = + { + .lEnd = DI_FFNOMINALMAX, + }; + IDirectInputEffect *effect; + struct effect *entry; + HRESULT hr; + + hr = IDirectInputDevice8_Acquire( device ); + if (FAILED(hr)) return DIENUM_CONTINUE; + + if (!(entry = calloc( 1, sizeof(*entry) ))) return DIENUM_STOP; + + if (IsEqualGUID( &info->guid, &GUID_RampForce )) + { + params.cbTypeSpecificParams = sizeof(ramp); + params.lpvTypeSpecificParams = &ramp; + params.dwFlags |= DIEP_TYPESPECIFICPARAMS; + } + else if (IsEqualGUID( &info->guid, &GUID_ConstantForce )) + { + params.cbTypeSpecificParams = sizeof(constant); + params.lpvTypeSpecificParams = &constant; + params.dwFlags |= DIEP_TYPESPECIFICPARAMS; + } + else if (IsEqualGUID( &info->guid, &GUID_Sine ) || + IsEqualGUID( &info->guid, &GUID_Square ) || + IsEqualGUID( &info->guid, &GUID_Triangle ) || + IsEqualGUID( &info->guid, &GUID_SawtoothUp ) || + IsEqualGUID( &info->guid, &GUID_SawtoothDown )) + { + params.cbTypeSpecificParams = sizeof(periodic); + params.lpvTypeSpecificParams = &periodic; + params.dwFlags |= DIEP_TYPESPECIFICPARAMS; + } + else if (IsEqualGUID( &info->guid, &GUID_Spring ) || + IsEqualGUID( &info->guid, &GUID_Damper ) || + IsEqualGUID( &info->guid, &GUID_Inertia ) || + IsEqualGUID( &info->guid, &GUID_Friction )) + { + params.cbTypeSpecificParams = sizeof(condition); + params.lpvTypeSpecificParams = &condition; + params.dwFlags |= DIEP_TYPESPECIFICPARAMS; + } + + do hr = IDirectInputDevice2_CreateEffect( device, &info->guid, ¶ms, &effect, NULL ); + while (FAILED(hr) && --params.cAxes); + + if (FAILED(hr)) + { + FIXME( "Failed to create effect with type %s, hr %#lx\n", debugstr_guid( &info->guid ), hr ); + free( entry ); + return DIENUM_CONTINUE; + } + + entry->effect = effect; + list_add_tail( &effects, &entry->entry ); + + return DIENUM_CONTINUE; +} + +static void set_selected_effect( IDirectInputEffect *effect ) +{ + IDirectInputEffect *previous;
EnterCriticalSection( &state_cs ); - modified = memcmp( &last_state, state, sizeof(*state) ) || - memcmp( &last_caps, caps, sizeof(*caps) ); - last_state = *state; - last_caps = *caps; + if ((previous = effect_selected)) IDirectInputEffect_Release( previous ); + if ((effect_selected = effect)) IDirectInput_AddRef( effect ); LeaveCriticalSection( &state_cs ); +} + +static IDirectInputEffect *get_selected_effect(void) +{ + IDirectInputEffect *effect; + + EnterCriticalSection( &state_cs ); + if ((effect = effect_selected)) IDirectInputEffect_AddRef( effect ); + LeaveCriticalSection( &state_cs ); + + return effect; +} + +static void clear_effects(void) +{ + struct effect *effect, *next;
- if (modified) SendMessageW( hwnd, WM_USER, 0, 0 ); + set_selected_effect( NULL ); + + LIST_FOR_EACH_ENTRY_SAFE( effect, next, &effects, struct effect, entry ) + { + list_remove( &effect->entry ); + IDirectInputEffect_Release( effect->effect ); + free( effect ); + } }
-static void get_device_state( DIJOYSTATE *state, DIDEVCAPS *caps ) +static void set_selected_device( IDirectInputDevice8W *device ) { + IDirectInputDevice8W *previous; + EnterCriticalSection( &state_cs ); - *state = last_state; - *caps = last_caps; + + set_selected_effect( NULL ); + + if ((previous = device_selected)) + { + IDirectInputDevice8_SetEventNotification( previous, NULL ); + IDirectInputDevice8_Release( previous ); + } + if ((device_selected = device)) + { + IDirectInputDevice8_AddRef( device ); + IDirectInputDevice8_SetEventNotification( device, state_event ); + IDirectInputDevice8_Acquire( device ); + } + LeaveCriticalSection( &state_cs ); }
+static IDirectInputDevice8W *get_selected_device(void) +{ + IDirectInputDevice8W *device; + + EnterCriticalSection( &state_cs ); + device = device_selected; + if (device) IDirectInputDevice8_AddRef( device ); + LeaveCriticalSection( &state_cs ); + + return device; +} + +static BOOL CALLBACK enum_devices( const DIDEVICEINSTANCEW *instance, void *context ) +{ + DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; + IDirectInput8W *dinput = context; + struct device *entry; + + if (!(entry = calloc( 1, sizeof(*entry) ))) return DIENUM_STOP; + + IDirectInput8_CreateDevice( dinput, &instance->guidInstance, &entry->device, NULL ); + IDirectInputDevice8_SetDataFormat( entry->device, &c_dfDIJoystick ); + IDirectInputDevice8_GetCapabilities( entry->device, &caps ); + + list_add_tail( &devices, &entry->entry ); + + return DIENUM_CONTINUE; +} + +static void clear_devices(void) +{ + struct device *entry, *next; + + set_selected_device( NULL ); + + LIST_FOR_EACH_ENTRY_SAFE( entry, next, &devices, struct device, entry ) + { + list_remove( &entry->entry ); + IDirectInputDevice8_Unacquire( entry->device ); + IDirectInputDevice8_Release( entry->device ); + free( entry ); + } +} + +static DWORD WINAPI input_thread( void *param ) +{ + HANDLE events[2] = {param, state_event}; + + while (WaitForMultipleObjects( 2, events, FALSE, INFINITE ) != 0) + { + IDirectInputEffect *effect; + DIJOYSTATE state = {0}; + unsigned int i; + + SendMessageW( dialog_hwnd, WM_USER, 0, 0 ); + + if ((effect = get_selected_effect())) + { + DWORD flags = DIEP_AXES | DIEP_DIRECTION | DIEP_NORESTART; + LONG direction[3] = {0}; + DWORD axes[3] = {0}; + DIEFFECT params = + { + .dwSize = sizeof(DIEFFECT), + .dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS, + .rglDirection = direction, + .rgdwAxes = axes, + .cAxes = 3, + }; + + IDirectInputEffect_GetParameters( effect, ¶ms, flags ); + params.rgdwAxes[0] = state.lX; + params.rgdwAxes[1] = state.lY; + + for (i = 0; i < ARRAY_SIZE(state.rgbButtons); i++) + { + if (state.rgbButtons[i]) + { + IDirectInputEffect_SetParameters( effect, ¶ms, flags ); + IDirectInputEffect_Start( effect, 1, 0 ); + break; + } + } + + IDirectInputEffect_Release( effect ); + } + } + + return 0; +} + static void draw_axis_view( HDC hdc, RECT rect, const WCHAR *name, LONG value ) { POINT center = @@ -167,7 +404,7 @@ static void draw_pov_view( HDC hdc, RECT rect, DWORD value ) if (value != -1) Polygon( hdc, points + value / 4500 * 2, 3 ); }
-static inline void draw_button_view( HDC hdc, RECT rect, BOOL set, const WCHAR *name ) +static void draw_button_view( HDC hdc, RECT rect, BOOL set, const WCHAR *name ) { COLORREF color; HFONT font; @@ -197,13 +434,19 @@ LRESULT CALLBACK test_di_axes_window_proc( HWND hwnd, UINT msg, WPARAM wparam, L
if (msg == WM_PAINT) { + DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; + IDirectInputDevice8W *device; + DIJOYSTATE state = {0}; RECT rect, tmp_rect; PAINTSTRUCT paint; - DIJOYSTATE state; - DIDEVCAPS caps; HDC hdc;
- get_device_state( &state, &caps ); + if ((device = get_selected_device())) + { + IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + IDirectInputDevice8_GetCapabilities( device, &caps ); + IDirectInputDevice8_Release( device ); + }
hdc = BeginPaint( hwnd, &paint );
@@ -257,13 +500,19 @@ LRESULT CALLBACK test_di_povs_window_proc( HWND hwnd, UINT msg, WPARAM wparam, L
if (msg == WM_PAINT) { + DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; + IDirectInputDevice8W *device; + DIJOYSTATE state = {0}; PAINTSTRUCT paint; - DIJOYSTATE state; - DIDEVCAPS caps; RECT rect; HDC hdc;
- get_device_state( &state, &caps ); + if ((device = get_selected_device())) + { + IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + IDirectInputDevice8_GetCapabilities( device, &caps ); + IDirectInputDevice8_Release( device ); + }
hdc = BeginPaint( hwnd, &paint );
@@ -294,14 +543,20 @@ LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam
if (msg == WM_PAINT) { + DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; UINT i, j, offs, size, step, space = 2; + IDirectInputDevice8W *device; + DIJOYSTATE state = {0}; PAINTSTRUCT paint; - DIJOYSTATE state; - DIDEVCAPS caps; RECT rect; HDC hdc;
- get_device_state( &state, &caps ); + if ((device = get_selected_device())) + { + IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); + IDirectInputDevice8_GetCapabilities( device, &caps ); + IDirectInputDevice8_Release( device ); + }
if (caps.dwButtons <= 48) step = 16; else step = 32; @@ -339,3 +594,218 @@ LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam
return DefWindowProcW( hwnd, msg, wparam, lparam ); } + +static void update_di_effects( HWND hwnd, IDirectInputDevice8W *device ) +{ + struct effect *effect; + + clear_effects(); + + IDirectInputDevice8_EnumEffects( device, enum_effects, device, 0 ); + + SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_RESETCONTENT, 0, 0 ); + SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_ADDSTRING, 0, (LPARAM)L"None" ); + + LIST_FOR_EACH_ENTRY( effect, &effects, struct effect, entry ) + { + DIEFFECTINFOW info = {.dwSize = sizeof(DIEFFECTINFOW)}; + GUID guid; + + if (FAILED(IDirectInputEffect_GetEffectGuid( effect->effect, &guid ))) continue; + if (FAILED(IDirectInputDevice8_GetEffectInfo( device, &info, &guid ))) continue; + SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_ADDSTRING, 0, (LPARAM)( info.tszName + 5 ) ); + } +} + +static void handle_di_effects_change( HWND hwnd ) +{ + IDirectInputDevice8W *device; + struct list *entry; + int sel; + + set_selected_effect( NULL ); + + sel = SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_GETCURSEL, 0, 0 ) - 1; + if (sel < 0) return; + + entry = list_head( &effects ); + while (sel-- && entry) entry = list_next( &effects, entry ); + if (!entry) return; + + set_selected_effect( LIST_ENTRY( entry, struct effect, entry )->effect ); + + if ((device = get_selected_device())) + { + IDirectInputDevice8_Unacquire( device ); + IDirectInputDevice8_SetCooperativeLevel( device, GetAncestor( hwnd, GA_ROOT ), DISCL_BACKGROUND | DISCL_EXCLUSIVE ); + IDirectInputDevice8_Acquire( device ); + IDirectInputDevice8_Release( device ); + } +} + +static void create_device_views( HWND hwnd ) +{ + HINSTANCE instance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ); + HWND parent; + LONG margin; + RECT rect; + + parent = GetDlgItem( hwnd, IDC_DI_AXES ); + GetClientRect( parent, &rect ); + rect.top += 10; + + margin = (rect.bottom - rect.top) * 10 / 100; + InflateRect( &rect, -margin, -margin ); + + CreateWindowW( L"JoyCplDInputAxes", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, parent, NULL, NULL, instance ); + + parent = GetDlgItem( hwnd, IDC_DI_POVS ); + GetClientRect( parent, &rect ); + rect.top += 10; + + margin = (rect.bottom - rect.top) * 10 / 100; + InflateRect( &rect, -margin, -margin ); + + CreateWindowW( L"JoyCplDInputPOVs", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, parent, NULL, NULL, instance ); + + parent = GetDlgItem( hwnd, IDC_DI_BUTTONS ); + GetClientRect( parent, &rect ); + rect.top += 10; + + margin = (rect.bottom - rect.top) * 10 / 100; + InflateRect( &rect, -margin, -margin ); + + CreateWindowW( L"JoyCplDInputButtons", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, parent, NULL, NULL, instance ); +} + +static void handle_di_devices_change( HWND hwnd ) +{ + DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; + IDirectInputDevice8W *device; + struct list *entry; + int i; + + set_selected_device( NULL ); + + i = SendDlgItemMessageW( hwnd, IDC_DI_DEVICES, CB_GETCURSEL, 0, 0 ); + if (i < 0) return; + + entry = list_head( &devices ); + while (i-- && entry) entry = list_next( &devices, entry ); + if (!entry) return; + + device = LIST_ENTRY( entry, struct device, entry )->device; + if (FAILED(IDirectInputDevice8_GetCapabilities( device, &caps ))) return; + + set_selected_device( device ); + update_di_effects( hwnd, device ); +} + +static void update_di_devices( HWND hwnd ) +{ + IDirectInput8W *dinput; + struct device *entry; + + clear_devices(); + + DirectInput8Create( GetModuleHandleW( NULL ), DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void **)&dinput, NULL ); + IDirectInput8_EnumDevices( dinput, DI8DEVCLASS_GAMECTRL, enum_devices, dinput, DIEDFL_ATTACHEDONLY ); + IDirectInput8_Release( dinput ); + + SendDlgItemMessageW( hwnd, IDC_DI_DEVICES, CB_RESETCONTENT, 0, 0 ); + + LIST_FOR_EACH_ENTRY( entry, &devices, struct device, entry ) + { + DIDEVICEINSTANCEW info = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + if (FAILED(IDirectInputDevice8_GetDeviceInfo( entry->device, &info ))) continue; + SendDlgItemMessageW( hwnd, IDC_DI_DEVICES, CB_ADDSTRING, 0, (LPARAM)info.tszInstanceName ); + } +} + +static void update_device_views( HWND hwnd ) +{ + HWND parent, view; + + parent = GetDlgItem( hwnd, IDC_DI_AXES ); + view = FindWindowExW( parent, NULL, L"JoyCplDInputAxes", NULL ); + InvalidateRect( view, NULL, TRUE ); + + parent = GetDlgItem( hwnd, IDC_DI_POVS ); + view = FindWindowExW( parent, NULL, L"JoyCplDInputPOVs", NULL ); + InvalidateRect( view, NULL, TRUE ); + + parent = GetDlgItem( hwnd, IDC_DI_BUTTONS ); + view = FindWindowExW( parent, NULL, L"JoyCplDInputButtons", NULL ); + InvalidateRect( view, NULL, TRUE ); +} + +INT_PTR CALLBACK test_di_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + static HANDLE thread, thread_stop; + + TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + switch (msg) + { + case WM_INITDIALOG: + create_device_views( hwnd ); + return TRUE; + + case WM_COMMAND: + switch (wparam) + { + case MAKEWPARAM( IDC_DI_DEVICES, CBN_SELCHANGE ): + handle_di_devices_change( hwnd ); + + SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_SETCURSEL, 0, 0 ); + handle_di_effects_change( hwnd ); + break; + + case MAKEWPARAM( IDC_DI_EFFECTS, LBN_SELCHANGE ): + handle_di_effects_change( hwnd ); + break; + } + return TRUE; + + case WM_NOTIFY: + switch (((NMHDR *)lparam)->code) + { + case PSN_SETACTIVE: + dialog_hwnd = hwnd; + state_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + thread_stop = CreateEventW( NULL, FALSE, FALSE, NULL ); + + update_di_devices( hwnd ); + + SendDlgItemMessageW( hwnd, IDC_DI_DEVICES, CB_SETCURSEL, 0, 0 ); + handle_di_devices_change( hwnd ); + + SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_SETCURSEL, 0, 0 ); + handle_di_effects_change( hwnd ); + + thread = CreateThread( NULL, 0, input_thread, (void *)thread_stop, 0, NULL ); + break; + + case PSN_RESET: + case PSN_KILLACTIVE: + SetEvent( thread_stop ); + MsgWaitForMultipleObjects( 1, &thread, FALSE, INFINITE, 0 ); + CloseHandle( state_event ); + CloseHandle( thread_stop ); + CloseHandle( thread ); + + clear_effects(); + clear_devices(); + break; + } + return TRUE; + + case WM_USER: + update_device_views( hwnd ); + return TRUE; + } + return FALSE; +} diff --git a/dlls/joy.cpl/joy_private.h b/dlls/joy.cpl/joy_private.h index 0dc9a02be9f..1b960c6ea16 100644 --- a/dlls/joy.cpl/joy_private.h +++ b/dlls/joy.cpl/joy_private.h @@ -30,7 +30,7 @@
#include "resource.h"
-extern void set_di_device_state( HWND hwnd, DIJOYSTATE *state, DIDEVCAPS *caps ); +extern INT_PTR CALLBACK test_di_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); extern LRESULT CALLBACK test_di_axes_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); extern LRESULT CALLBACK test_di_povs_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); extern LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); diff --git a/dlls/joy.cpl/main.c b/dlls/joy.cpl/main.c index fb41a8a2860..8e8d167068e 100644 --- a/dlls/joy.cpl/main.c +++ b/dlls/joy.cpl/main.c @@ -38,35 +38,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(joycpl);
-#define TEST_MAX_BUTTONS 32 -#define TEST_POLL_TIME 100 - -#define FF_PLAY_TIME 2*DI_SECONDS -#define FF_PERIOD_TIME FF_PLAY_TIME/4 - -struct effect -{ - struct list entry; - IDirectInputEffect *effect; -}; - struct device { struct list entry; IDirectInputDevice8W *device; };
-struct Graphics -{ - HWND hwnd; -}; - struct JoystickData { IDirectInput8W *di; - struct Graphics graphics; - HWND di_dialog_hwnd; - BOOL stop; };
static HMODULE hcpl; @@ -80,13 +60,7 @@ static CRITICAL_SECTION_DEBUG joy_cs_debug = }; static CRITICAL_SECTION joy_cs = { &joy_cs_debug, -1, 0, 0, 0, 0 };
-static struct list effects = LIST_INIT( effects ); -static IDirectInputEffect *effect_selected; - static struct list devices = LIST_INIT( devices ); -static IDirectInputDevice8W *device_selected; - -static HANDLE device_state_event;
/********************************************************************* * DllMain @@ -104,133 +78,6 @@ BOOL WINAPI DllMain(HINSTANCE hdll, DWORD reason, LPVOID reserved) return TRUE; }
-static BOOL CALLBACK enum_effects( const DIEFFECTINFOW *info, void *context ) -{ - IDirectInputDevice8W *device = context; - DWORD axes[2] = {DIJOFS_X, DIJOFS_Y}; - LONG direction[2] = {0}; - DIEFFECT params = - { - .dwSize = sizeof(DIEFFECT), - .dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS, - .dwDuration = FF_PLAY_TIME, - .dwGain = DI_FFNOMINALMAX, - .rglDirection = direction, - .rgdwAxes = axes, - .cAxes = 2, - }; - DICONSTANTFORCE constant = - { - .lMagnitude = DI_FFNOMINALMAX, - }; - DIPERIODIC periodic = - { - .dwMagnitude = DI_FFNOMINALMAX, - .dwPeriod = FF_PERIOD_TIME, - }; - DICONDITION condition = - { - .dwPositiveSaturation = 10000, - .dwNegativeSaturation = 10000, - .lPositiveCoefficient = 10000, - .lNegativeCoefficient = 10000, - }; - DIRAMPFORCE ramp = - { - .lEnd = DI_FFNOMINALMAX, - }; - IDirectInputEffect *effect; - struct effect *entry; - HRESULT hr; - - hr = IDirectInputDevice8_Acquire( device ); - if (FAILED(hr)) return DIENUM_CONTINUE; - - if (!(entry = calloc( 1, sizeof(*entry) ))) return DIENUM_STOP; - - if (IsEqualGUID( &info->guid, &GUID_RampForce )) - { - params.cbTypeSpecificParams = sizeof(ramp); - params.lpvTypeSpecificParams = &ramp; - params.dwFlags |= DIEP_TYPESPECIFICPARAMS; - } - else if (IsEqualGUID( &info->guid, &GUID_ConstantForce )) - { - params.cbTypeSpecificParams = sizeof(constant); - params.lpvTypeSpecificParams = &constant; - params.dwFlags |= DIEP_TYPESPECIFICPARAMS; - } - else if (IsEqualGUID( &info->guid, &GUID_Sine ) || - IsEqualGUID( &info->guid, &GUID_Square ) || - IsEqualGUID( &info->guid, &GUID_Triangle ) || - IsEqualGUID( &info->guid, &GUID_SawtoothUp ) || - IsEqualGUID( &info->guid, &GUID_SawtoothDown )) - { - params.cbTypeSpecificParams = sizeof(periodic); - params.lpvTypeSpecificParams = &periodic; - params.dwFlags |= DIEP_TYPESPECIFICPARAMS; - } - else if (IsEqualGUID( &info->guid, &GUID_Spring ) || - IsEqualGUID( &info->guid, &GUID_Damper ) || - IsEqualGUID( &info->guid, &GUID_Inertia ) || - IsEqualGUID( &info->guid, &GUID_Friction )) - { - params.cbTypeSpecificParams = sizeof(condition); - params.lpvTypeSpecificParams = &condition; - params.dwFlags |= DIEP_TYPESPECIFICPARAMS; - } - - do hr = IDirectInputDevice2_CreateEffect( device, &info->guid, ¶ms, &effect, NULL ); - while (FAILED(hr) && --params.cAxes); - - if (FAILED(hr)) - { - FIXME( "Failed to create effect with type %s, hr %#lx\n", debugstr_guid( &info->guid ), hr ); - free( entry ); - return DIENUM_CONTINUE; - } - - entry->effect = effect; - list_add_tail( &effects, &entry->entry ); - - return DIENUM_CONTINUE; -} - -static void set_selected_effect( IDirectInputEffect *effect ) -{ - IDirectInputEffect *previous; - - EnterCriticalSection( &joy_cs ); - if ((previous = effect_selected)) IDirectInputEffect_Release( previous ); - if ((effect_selected = effect)) IDirectInput_AddRef( effect ); - LeaveCriticalSection( &joy_cs ); -} - -static IDirectInputEffect *get_selected_effect(void) -{ - IDirectInputEffect *effect; - - EnterCriticalSection( &joy_cs ); - if ((effect = effect_selected)) IDirectInputEffect_AddRef( effect ); - LeaveCriticalSection( &joy_cs ); - - return effect; -} - -static void clear_effects(void) -{ - struct effect *effect, *next; - - set_selected_effect( NULL ); - - LIST_FOR_EACH_ENTRY_SAFE( effect, next, &effects, struct effect, entry ) - { - list_remove( &effect->entry ); - IDirectInputEffect_Release( effect->effect ); - free( effect ); - } -} - static BOOL CALLBACK enum_devices( const DIDEVICEINSTANCEW *instance, void *context ) { DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; @@ -248,47 +95,10 @@ static BOOL CALLBACK enum_devices( const DIDEVICEINSTANCEW *instance, void *cont return DIENUM_CONTINUE; }
-static void set_selected_device( IDirectInputDevice8W *device ) -{ - IDirectInputDevice8W *previous; - - EnterCriticalSection( &joy_cs ); - - set_selected_effect( NULL ); - - if ((previous = device_selected)) - { - IDirectInputDevice8_SetEventNotification( previous, NULL ); - IDirectInputDevice8_Release( previous ); - } - if ((device_selected = device)) - { - IDirectInputDevice8_AddRef( device ); - IDirectInputDevice8_SetEventNotification( device, device_state_event ); - IDirectInputDevice8_Acquire( device ); - } - - LeaveCriticalSection( &joy_cs ); -} - -static IDirectInputDevice8W *get_selected_device(void) -{ - IDirectInputDevice8W *device; - - EnterCriticalSection( &joy_cs ); - device = device_selected; - if (device) IDirectInputDevice8_AddRef( device ); - LeaveCriticalSection( &joy_cs ); - - return device; -} - static void clear_devices(void) { struct device *entry, *next;
- set_selected_device( NULL ); - LIST_FOR_EACH_ENTRY_SAFE( entry, next, &devices, struct device, entry ) { list_remove( &entry->entry ); @@ -368,7 +178,6 @@ static void refresh_joystick_list(HWND hwnd, struct JoystickData *data) LSTATUS status; DWORD i;
- clear_effects(); clear_devices();
IDirectInput8_EnumDevices( data->di, DI8DEVCLASS_GAMECTRL, enum_devices, data, DIEDFL_ATTACHEDONLY ); @@ -455,9 +264,6 @@ static INT_PTR CALLBACK list_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM EnableWindow(GetDlgItem(hwnd, IDC_BUTTONRESET), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_BUTTONOVERRIDE), FALSE);
- /* Store the hwnd to be used with MapDialogRect for unit conversions */ - data->graphics.hwnd = hwnd; - return TRUE; }
@@ -554,303 +360,6 @@ static INT_PTR CALLBACK list_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM return FALSE; }
-/********************************************************************* - * Joystick testing functions - * - */ -static void dump_joy_state(DIJOYSTATE* st) -{ - int i; - TRACE("Ax (% 5ld,% 5ld,% 5ld)\n", st->lX,st->lY, st->lZ); - TRACE("RAx (% 5ld,% 5ld,% 5ld)\n", st->lRx, st->lRy, st->lRz); - TRACE("Slider (% 5ld,% 5ld)\n", st->rglSlider[0], st->rglSlider[1]); - TRACE("Pov (% 5ld,% 5ld,% 5ld,% 5ld)\n", st->rgdwPOV[0], st->rgdwPOV[1], st->rgdwPOV[2], st->rgdwPOV[3]); - - TRACE("Buttons "); - for(i=0; i < TEST_MAX_BUTTONS; i++) - TRACE(" %c",st->rgbButtons[i] ? 'x' : 'o'); - TRACE("\n"); -} - -static DWORD WINAPI input_thread(void *param) -{ - struct JoystickData *data = param; - - while (!data->stop) - { - IDirectInputDevice8W *device; - IDirectInputEffect *effect; - DIJOYSTATE state = {0}; - unsigned int i; - - if (WaitForSingleObject( device_state_event, TEST_POLL_TIME ) == WAIT_TIMEOUT) continue; - - if ((device = get_selected_device())) - { - DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; - - IDirectInputDevice8_GetDeviceState( device, sizeof(state), &state ); - IDirectInputDevice8_GetCapabilities( device, &caps ); - IDirectInputDevice8_Release( device ); - - dump_joy_state(&state); - set_di_device_state( data->di_dialog_hwnd, &state, &caps ); - } - - if ((effect = get_selected_effect())) - { - DWORD flags = DIEP_AXES | DIEP_DIRECTION | DIEP_NORESTART; - LONG direction[3] = {0}; - DWORD axes[3] = {0}; - DIEFFECT params = - { - .dwSize = sizeof(DIEFFECT), - .dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS, - .rglDirection = direction, - .rgdwAxes = axes, - .cAxes = 3, - }; - - IDirectInputEffect_GetParameters( effect, ¶ms, flags ); - params.rgdwAxes[0] = state.lX; - params.rgdwAxes[1] = state.lY; - - for (i=0; i < TEST_MAX_BUTTONS; i++) - { - if (state.rgbButtons[i]) - { - IDirectInputEffect_SetParameters( effect, ¶ms, flags ); - IDirectInputEffect_Start( effect, 1, 0 ); - break; - } - } - - IDirectInputEffect_Release( effect ); - } - } - - return 0; -} - -static void initialize_effects_list( HWND hwnd, IDirectInputDevice8W *device ) -{ - struct effect *effect; - - clear_effects(); - - IDirectInputDevice8_EnumEffects( device, enum_effects, device, 0 ); - - SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_RESETCONTENT, 0, 0 ); - SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_ADDSTRING, 0, (LPARAM)L"None" ); - - LIST_FOR_EACH_ENTRY( effect, &effects, struct effect, entry ) - { - DIEFFECTINFOW info = {.dwSize = sizeof(DIEFFECTINFOW)}; - GUID guid; - - if (FAILED(IDirectInputEffect_GetEffectGuid( effect->effect, &guid ))) continue; - if (FAILED(IDirectInputDevice8_GetEffectInfo( device, &info, &guid ))) continue; - SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_ADDSTRING, 0, (LPARAM)( info.tszName + 5 ) ); - } -} - -static void test_handle_joychange(HWND hwnd, struct JoystickData *data) -{ - DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; - IDirectInputDevice8W *device; - DIJOYSTATE state = {0}; - struct list *entry; - int i; - - set_selected_device( NULL ); - - i = SendDlgItemMessageW( hwnd, IDC_DI_DEVICES, CB_GETCURSEL, 0, 0 ); - if (i < 0) return; - - entry = list_head( &devices ); - while (i-- && entry) entry = list_next( &devices, entry ); - if (!entry) return; - - device = LIST_ENTRY( entry, struct device, entry )->device; - if (FAILED(IDirectInputDevice8_GetCapabilities( device, &caps ))) return; - - set_di_device_state( data->di_dialog_hwnd, &state, &caps ); - set_selected_device( device ); - initialize_effects_list( hwnd, device ); -} - -static void ff_handle_effectchange( HWND hwnd ) -{ - IDirectInputDevice8W *device; - struct list *entry; - int sel; - - set_selected_effect( NULL ); - - sel = SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_GETCURSEL, 0, 0 ) - 1; - if (sel < 0) return; - - entry = list_head( &effects ); - while (sel-- && entry) entry = list_next( &effects, entry ); - if (!entry) return; - - set_selected_effect( LIST_ENTRY( entry, struct effect, entry )->effect ); - - if ((device = get_selected_device())) - { - IDirectInputDevice8_Unacquire( device ); - IDirectInputDevice8_SetCooperativeLevel( device, GetAncestor( hwnd, GA_ROOT ), DISCL_BACKGROUND | DISCL_EXCLUSIVE ); - IDirectInputDevice8_Acquire( device ); - IDirectInputDevice8_Release( device ); - } -} - -/********************************************************************* - * test_dlgproc [internal] - * - */ -static void di_update_select_combo( HWND hwnd ) -{ - struct device *entry; - - SendDlgItemMessageW( hwnd, IDC_DI_DEVICES, CB_RESETCONTENT, 0, 0 ); - - LIST_FOR_EACH_ENTRY( entry, &devices, struct device, entry ) - { - DIDEVICEINSTANCEW info = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; - if (FAILED(IDirectInputDevice8_GetDeviceInfo( entry->device, &info ))) continue; - SendDlgItemMessageW( hwnd, IDC_DI_DEVICES, CB_ADDSTRING, 0, (LPARAM)info.tszInstanceName ); - } -} - -static void update_device_views( HWND hwnd ) -{ - HWND parent, view; - - parent = GetDlgItem( hwnd, IDC_DI_AXES ); - view = FindWindowExW( parent, NULL, L"JoyCplDInputAxes", NULL ); - InvalidateRect( view, NULL, TRUE ); - - parent = GetDlgItem( hwnd, IDC_DI_POVS ); - view = FindWindowExW( parent, NULL, L"JoyCplDInputPOVs", NULL ); - InvalidateRect( view, NULL, TRUE ); - - parent = GetDlgItem( hwnd, IDC_DI_BUTTONS ); - view = FindWindowExW( parent, NULL, L"JoyCplDInputButtons", NULL ); - InvalidateRect( view, NULL, TRUE ); -} - -static void create_device_views( HWND hwnd ) -{ - HINSTANCE instance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ); - HWND parent; - LONG margin; - RECT rect; - - parent = GetDlgItem( hwnd, IDC_DI_AXES ); - GetClientRect( parent, &rect ); - rect.top += 10; - - margin = (rect.bottom - rect.top) * 10 / 100; - InflateRect( &rect, -margin, -margin ); - - CreateWindowW( L"JoyCplDInputAxes", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, parent, NULL, NULL, instance ); - - parent = GetDlgItem( hwnd, IDC_DI_POVS ); - GetClientRect( parent, &rect ); - rect.top += 10; - - margin = (rect.bottom - rect.top) * 10 / 100; - InflateRect( &rect, -margin, -margin ); - - CreateWindowW( L"JoyCplDInputPOVs", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, parent, NULL, NULL, instance ); - - parent = GetDlgItem( hwnd, IDC_DI_BUTTONS ); - GetClientRect( parent, &rect ); - rect.top += 10; - - margin = (rect.bottom - rect.top) * 10 / 100; - InflateRect( &rect, -margin, -margin ); - - CreateWindowW( L"JoyCplDInputButtons", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, parent, NULL, NULL, instance ); -} - -static INT_PTR CALLBACK test_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) -{ - static HANDLE thread; - static struct JoystickData *data; - TRACE("(%p, 0x%08x/%d, 0x%Ix)\n", hwnd, msg, msg, lparam); - - switch (msg) - { - case WM_INITDIALOG: - { - data = (struct JoystickData*) ((PROPSHEETPAGEW*)lparam)->lParam; - - di_update_select_combo( hwnd ); - create_device_views( hwnd ); - - return TRUE; - } - - case WM_COMMAND: - switch(wparam) - { - case MAKEWPARAM( IDC_DI_DEVICES, CBN_SELCHANGE ): - test_handle_joychange( hwnd, data ); - - SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_SETCURSEL, 0, 0 ); - ff_handle_effectchange( hwnd ); - break; - - case MAKEWPARAM( IDC_DI_EFFECTS, LBN_SELCHANGE ): - ff_handle_effectchange( hwnd ); - break; - } - return TRUE; - - case WM_NOTIFY: - switch(((LPNMHDR)lparam)->code) - { - case PSN_SETACTIVE: - { - DWORD tid; - - di_update_select_combo( hwnd ); - - data->stop = FALSE; - data->di_dialog_hwnd = hwnd; - - /* Set the first joystick as default */ - SendDlgItemMessageW( hwnd, IDC_DI_DEVICES, CB_SETCURSEL, 0, 0 ); - test_handle_joychange(hwnd, data); - - SendDlgItemMessageW( hwnd, IDC_DI_EFFECTS, LB_SETCURSEL, 0, 0 ); - ff_handle_effectchange( hwnd ); - - thread = CreateThread(NULL, 0, input_thread, (void*) data, 0, &tid); - } - break; - - case PSN_RESET: /* intentional fall-through */ - case PSN_KILLACTIVE: - /* Stop input thread */ - data->stop = TRUE; - MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, 0); - CloseHandle(thread); - break; - } - return TRUE; - - case WM_USER: - update_device_views( hwnd ); - return TRUE; - } - return FALSE; -}
/****************************************************************************** * propsheet_callback [internal] @@ -886,7 +395,7 @@ static void display_cpl_sheets( HWND parent, struct JoystickData *data ) .dwSize = sizeof(PROPSHEETPAGEW), .hInstance = hcpl, .pszTemplate = MAKEINTRESOURCEW( IDD_TEST_DI ), - .pfnDlgProc = test_dlgproc, + .pfnDlgProc = test_di_dialog_proc, .lParam = (INT_PTR)data, }, { @@ -1000,7 +509,6 @@ LONG CALLBACK CPlApplet(HWND hwnd, UINT command, LPARAM lParam1, LPARAM lParam2) HRESULT hr;
register_window_class(); - device_state_event = CreateEventW( NULL, FALSE, FALSE, NULL );
/* Initialize dinput */ hr = DirectInput8Create(GetModuleHandleW(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void**)&data.di, NULL); @@ -1034,13 +542,11 @@ LONG CALLBACK CPlApplet(HWND hwnd, UINT command, LPARAM lParam1, LPARAM lParam2) break;
case CPL_STOP: - clear_effects(); clear_devices();
/* And destroy dinput too */ IDirectInput8_Release(data.di);
- CloseHandle( device_state_event ); unregister_window_class(); break; }