From: Rémi Bernon rbernon@codeweavers.com
--- dlls/windows.gaming.input/controller.c | 6 +++--- dlls/windows.gaming.input/provider.c | 7 +++++++ dlls/windows.gaming.input/provider.idl | 2 ++ 3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c index e1749a3032d..2276b9e947e 100644 --- a/dlls/windows.gaming.input/controller.c +++ b/dlls/windows.gaming.input/controller.c @@ -362,10 +362,10 @@ static HRESULT WINAPI raw_controller_2_get_SimpleHapticsControllers( IRawGameCon return hr; }
-static HRESULT WINAPI raw_controller_2_get_NonRoamableId( IRawGameController2 *iface, HSTRING* value ) +static HRESULT WINAPI raw_controller_2_get_NonRoamableId( IRawGameController2 *iface, HSTRING *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct controller *impl = impl_from_IRawGameController2( iface ); + return IWineGameControllerProvider_get_NonRoamableId( impl->wine_provider, value ); }
static HRESULT WINAPI raw_controller_2_get_DisplayName( IRawGameController2 *iface, HSTRING* value ) diff --git a/dlls/windows.gaming.input/provider.c b/dlls/windows.gaming.input/provider.c index 6908d733a53..4bedde992a7 100644 --- a/dlls/windows.gaming.input/provider.c +++ b/dlls/windows.gaming.input/provider.c @@ -141,6 +141,12 @@ static HRESULT WINAPI wine_provider_GetTrustLevel( IWineGameControllerProvider * return E_NOTIMPL; }
+static HRESULT WINAPI wine_provider_get_NonRoamableId( IWineGameControllerProvider *iface, HSTRING *value ) +{ + FIXME( "iface %p, value %p stub!\n", iface, value ); + return E_NOTIMPL; +} + static BOOL CALLBACK count_ffb_axes( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) { DWORD *count = args; @@ -354,6 +360,7 @@ static const struct IWineGameControllerProviderVtbl wine_provider_vtbl = wine_provider_GetRuntimeClassName, wine_provider_GetTrustLevel, /* IWineGameControllerProvider methods */ + wine_provider_get_NonRoamableId, wine_provider_get_Type, wine_provider_get_AxisCount, wine_provider_get_ButtonCount, diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl index 235c509b25f..54f848e51d4 100644 --- a/dlls/windows.gaming.input/provider.idl +++ b/dlls/windows.gaming.input/provider.idl @@ -169,6 +169,8 @@ namespace Windows.Gaming.Input.Custom { interface IWineGameControllerProvider : IInspectable requires Windows.Gaming.Input.Custom.IGameControllerProvider { + [propget] HRESULT NonRoamableId([out, retval] HSTRING *value); + [propget] HRESULT Type([out, retval] WineGameControllerType *value); [propget] HRESULT AxisCount([out, retval] INT32 *value); [propget] HRESULT ButtonCount([out, retval] INT32 *value);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/windows.gaming.input/controller.c | 6 +++--- dlls/windows.gaming.input/provider.c | 13 +++++++++++++ dlls/windows.gaming.input/provider.idl | 1 + 3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/dlls/windows.gaming.input/controller.c b/dlls/windows.gaming.input/controller.c index 2276b9e947e..7e7b570d7f6 100644 --- a/dlls/windows.gaming.input/controller.c +++ b/dlls/windows.gaming.input/controller.c @@ -368,10 +368,10 @@ static HRESULT WINAPI raw_controller_2_get_NonRoamableId( IRawGameController2 *i return IWineGameControllerProvider_get_NonRoamableId( impl->wine_provider, value ); }
-static HRESULT WINAPI raw_controller_2_get_DisplayName( IRawGameController2 *iface, HSTRING* value ) +static HRESULT WINAPI raw_controller_2_get_DisplayName( IRawGameController2 *iface, HSTRING *value ) { - FIXME( "iface %p, value %p stub!\n", iface, value ); - return E_NOTIMPL; + struct controller *impl = impl_from_IRawGameController2( iface ); + return IWineGameControllerProvider_get_DisplayName( impl->wine_provider, value ); }
static const struct IRawGameController2Vtbl raw_controller_2_vtbl = diff --git a/dlls/windows.gaming.input/provider.c b/dlls/windows.gaming.input/provider.c index 4bedde992a7..69737dbafbd 100644 --- a/dlls/windows.gaming.input/provider.c +++ b/dlls/windows.gaming.input/provider.c @@ -147,6 +147,18 @@ static HRESULT WINAPI wine_provider_get_NonRoamableId( IWineGameControllerProvid return E_NOTIMPL; }
+static HRESULT WINAPI wine_provider_get_DisplayName( IWineGameControllerProvider *iface, HSTRING *value ) +{ + struct provider *impl = impl_from_IWineGameControllerProvider( iface ); + DIDEVICEINSTANCEW instance = {.dwSize = sizeof(DIDEVICEINSTANCEW)}; + HRESULT hr; + + TRACE( "iface %p, value %p\n", iface, value ); + + if (FAILED(hr = IDirectInputDevice8_GetDeviceInfo( impl->dinput_device, &instance ))) return hr; + return WindowsCreateString( instance.tszProductName, wcslen( instance.tszProductName ), value ); +} + static BOOL CALLBACK count_ffb_axes( const DIDEVICEOBJECTINSTANCEW *obj, void *args ) { DWORD *count = args; @@ -361,6 +373,7 @@ static const struct IWineGameControllerProviderVtbl wine_provider_vtbl = wine_provider_GetTrustLevel, /* IWineGameControllerProvider methods */ wine_provider_get_NonRoamableId, + wine_provider_get_DisplayName, wine_provider_get_Type, wine_provider_get_AxisCount, wine_provider_get_ButtonCount, diff --git a/dlls/windows.gaming.input/provider.idl b/dlls/windows.gaming.input/provider.idl index 54f848e51d4..1d8134dff32 100644 --- a/dlls/windows.gaming.input/provider.idl +++ b/dlls/windows.gaming.input/provider.idl @@ -170,6 +170,7 @@ namespace Windows.Gaming.Input.Custom { requires Windows.Gaming.Input.Custom.IGameControllerProvider { [propget] HRESULT NonRoamableId([out, retval] HSTRING *value); + [propget] HRESULT DisplayName([out, retval] HSTRING *value);
[propget] HRESULT Type([out, retval] WineGameControllerType *value); [propget] HRESULT AxisCount([out, retval] INT32 *value);
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/joy.cpl/xinput.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/joy.cpl/xinput.c b/dlls/joy.cpl/xinput.c index f652c9ad171..2285485ae44 100644 --- a/dlls/joy.cpl/xinput.c +++ b/dlls/joy.cpl/xinput.c @@ -95,7 +95,7 @@ static DWORD WINAPI input_thread_proc( void *param ) struct device_state state = {0};
state.status = XInputGetCapabilities( i, 0, &state.caps ); - if (!state.status) state.status = XInputGetState( i, &state.state ); + if (!state.status) state.status = XInputGetStateEx( i, &state.state ); set_device_state( i, &state );
if (state.rumble)
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/joy.cpl/Makefile.in | 3 +- dlls/joy.cpl/joy.rc | 9 ++ dlls/joy.cpl/joy_private.h | 2 + dlls/joy.cpl/main.c | 6 + dlls/joy.cpl/resource.h | 4 + dlls/joy.cpl/wginput.c | 261 +++++++++++++++++++++++++++++++++++++ 6 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 dlls/joy.cpl/wginput.c
diff --git a/dlls/joy.cpl/Makefile.in b/dlls/joy.cpl/Makefile.in index ad8f0db16b0..74fbadd72d8 100644 --- a/dlls/joy.cpl/Makefile.in +++ b/dlls/joy.cpl/Makefile.in @@ -1,5 +1,5 @@ MODULE = joy.cpl -IMPORTS = dxguid dinput dinput8 ole32 comctl32 user32 gdi32 advapi32 xinput +IMPORTS = dxguid dinput dinput8 ole32 comctl32 user32 gdi32 advapi32 xinput combase
EXTRADLLFLAGS = -Wb,--prefer-native
@@ -8,4 +8,5 @@ SOURCES = \ joy.rc \ joy.svg \ main.c \ + wginput.c \ xinput.c diff --git a/dlls/joy.cpl/joy.rc b/dlls/joy.cpl/joy.rc index b9f244b6518..be6aa8bd09c 100644 --- a/dlls/joy.cpl/joy.rc +++ b/dlls/joy.cpl/joy.rc @@ -100,6 +100,15 @@ FONT 8, "Ms Shell Dlg" AUTOCHECKBOX "Rumble", IDC_XI_RUMBLE_3, 260, 220, 40, 10 }
+IDD_TEST_WGI DIALOG 0, 0, 320, 300 +STYLE WS_CAPTION | WS_CHILD | WS_DISABLED +CAPTION "Windows.Gaming.Input" +FONT 8, "Ms Shell Dlg" +{ + COMBOBOX IDC_WGI_DEVICES, 15, 10, 150, 60, CBS_DROPDOWNLIST | CBS_HASSTRINGS + COMBOBOX IDC_WGI_INTERFACE, 175, 10, 131, 60, CBS_DROPDOWNLIST | CBS_HASSTRINGS +} + LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
/* @makedep: joy.manifest */ diff --git a/dlls/joy.cpl/joy_private.h b/dlls/joy.cpl/joy_private.h index 1b960c6ea16..fa320bff423 100644 --- a/dlls/joy.cpl/joy_private.h +++ b/dlls/joy.cpl/joy_private.h @@ -38,4 +38,6 @@ extern LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM extern INT_PTR CALLBACK test_xi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); extern LRESULT CALLBACK test_xi_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam );
+extern INT_PTR CALLBACK test_wgi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); + #endif /* __JOY_PRIVATE_H */ diff --git a/dlls/joy.cpl/main.c b/dlls/joy.cpl/main.c index 11fc78f1038..d6936180063 100644 --- a/dlls/joy.cpl/main.c +++ b/dlls/joy.cpl/main.c @@ -449,6 +449,12 @@ static void display_cpl_sheets( HWND parent ) .pszTemplate = MAKEINTRESOURCEW( IDD_TEST_XI ), .pfnDlgProc = test_xi_dialog_proc, }, + { + .dwSize = sizeof(PROPSHEETPAGEW), + .hInstance = hcpl, + .pszTemplate = MAKEINTRESOURCEW( IDD_TEST_WGI ), + .pfnDlgProc = test_wgi_dialog_proc, + }, }; PROPSHEETHEADERW header = { diff --git a/dlls/joy.cpl/resource.h b/dlls/joy.cpl/resource.h index d2c16a27288..6b4b865f182 100644 --- a/dlls/joy.cpl/resource.h +++ b/dlls/joy.cpl/resource.h @@ -37,6 +37,7 @@ #define IDD_LIST 1000 #define IDD_TEST_DI 1001 #define IDD_TEST_XI 1002 +#define IDD_TEST_WGI 1003
#define IDC_DI_ENABLED_LIST 2000 #define IDC_XI_ENABLED_LIST 2001 @@ -69,6 +70,9 @@ #define IDC_XI_RUMBLE_2 2222 #define IDC_XI_RUMBLE_3 2223
+#define IDC_WGI_DEVICES 2300 +#define IDC_WGI_INTERFACE 2301 + #define ICO_MAIN 100
#endif diff --git a/dlls/joy.cpl/wginput.c b/dlls/joy.cpl/wginput.c new file mode 100644 index 00000000000..e033d021fe5 --- /dev/null +++ b/dlls/joy.cpl/wginput.c @@ -0,0 +1,261 @@ +/* + * Copyright 2022 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include "stdarg.h" +#include "stddef.h" + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" + +#include "winstring.h" +#include "roapi.h" + +#include "initguid.h" +#define WIDL_using_Windows_Foundation +#define WIDL_using_Windows_Foundation_Collections +#define WIDL_using_Windows_Foundation_Numerics +#include "windows.foundation.h" +#define WIDL_using_Windows_Devices_Power +#define WIDL_using_Windows_Gaming_Input +#include "windows.gaming.input.h" + +#include "wine/debug.h" +#include "wine/list.h" + +#include "joy_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(joycpl); + +struct device +{ + struct list entry; + IRawGameController *device; +}; + +static CRITICAL_SECTION state_cs; +static CRITICAL_SECTION_DEBUG state_cs_debug = +{ + 0, 0, &state_cs, + { &state_cs_debug.ProcessLocksList, &state_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": state_cs") } +}; +static CRITICAL_SECTION state_cs = { &state_cs_debug, -1, 0, 0, 0, 0 }; + +static struct list devices = LIST_INIT( devices ); +static IRawGameController *device_selected; + +static HWND dialog_hwnd; +static HANDLE state_event; + +static void set_selected_device( IRawGameController *device ) +{ + IRawGameController *previous; + + EnterCriticalSection( &state_cs ); + + if ((previous = device_selected)) IRawGameController_Release( previous ); + if ((device_selected = device)) IRawGameController_AddRef( device ); + + LeaveCriticalSection( &state_cs ); +} + +static inline IRawGameController *get_selected_device(void) +{ + IRawGameController *device; + + EnterCriticalSection( &state_cs ); + device = device_selected; + if (device) IRawGameController_AddRef( device ); + LeaveCriticalSection( &state_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 ); + IRawGameController_Release( entry->device ); + free( entry ); + } +} + +static DWORD WINAPI input_thread_proc( void *param ) +{ + HANDLE stop_event = param; + + while (WaitForSingleObject( stop_event, 20 ) == WAIT_TIMEOUT) + { + } + + return 0; +} + +static void handle_wgi_devices_change( HWND hwnd ) +{ + IRawGameController *device; + struct list *entry; + int i; + + set_selected_device( NULL ); + + i = SendDlgItemMessageW( hwnd, IDC_WGI_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; + set_selected_device( device ); +} + +static void update_wgi_devices( HWND hwnd ) +{ + static const WCHAR *class_name = RuntimeClass_Windows_Gaming_Input_RawGameController; + IVectorView_RawGameController *controllers; + IRawGameControllerStatics *statics; + struct device *entry; + HSTRING str; + UINT size; + + clear_devices(); + + WindowsCreateString( class_name, wcslen( class_name ), &str ); + RoGetActivationFactory( str, &IID_IRawGameControllerStatics, (void **)&statics ); + WindowsDeleteString( str ); + + IRawGameControllerStatics_get_RawGameControllers( statics, &controllers ); + IVectorView_RawGameController_get_Size( controllers, &size ); + + while (size--) + { + struct device *entry; + if (!(entry = calloc( 1, sizeof(struct device) ))) break; + IVectorView_RawGameController_GetAt( controllers, size, &entry->device ); + list_add_tail( &devices, &entry->entry ); + } + + IVectorView_RawGameController_Release( controllers ); + IRawGameControllerStatics_Release( statics ); + + SendDlgItemMessageW( hwnd, IDC_WGI_DEVICES, CB_RESETCONTENT, 0, 0 ); + + LIST_FOR_EACH_ENTRY( entry, &devices, struct device, entry ) + { + IRawGameController2 *controller2; + + if (SUCCEEDED(IRawGameController_QueryInterface( entry->device, &IID_IRawGameController2, + (void **)&controller2 ))) + { + HSTRING name; + + IRawGameController2_get_DisplayName( controller2, &name ); + SendDlgItemMessageW( hwnd, IDC_WGI_DEVICES, CB_ADDSTRING, 0, + (LPARAM)WindowsGetStringRawBuffer( name, NULL ) ); + WindowsDeleteString( name ); + + IRawGameController2_Release( controller2 ); + } + else + { + UINT16 vid = -1, pid = -1; + WCHAR buffer[256]; + + IRawGameController_get_HardwareVendorId( entry->device, &vid ); + IRawGameController_get_HardwareProductId( entry->device, &pid ); + + swprintf( buffer, ARRAY_SIZE(buffer), L"RawGameController %04x:%04x", vid, pid ); + SendDlgItemMessageW( hwnd, IDC_WGI_DEVICES, CB_ADDSTRING, 0, (LPARAM)buffer ); + } + } +} + +static void create_device_views( HWND hwnd ) +{ +} + +extern INT_PTR CALLBACK test_wgi_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_WGI_DEVICES, CBN_SELCHANGE ): + handle_wgi_devices_change( hwnd ); + break; + } + return TRUE; + + + case WM_NOTIFY: + switch (((NMHDR *)lparam)->code) + { + case PSN_SETACTIVE: + RoInitialize( RO_INIT_MULTITHREADED ); + + dialog_hwnd = hwnd; + state_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + thread_stop = CreateEventW( NULL, FALSE, FALSE, NULL ); + + update_wgi_devices( hwnd ); + + SendDlgItemMessageW( hwnd, IDC_WGI_DEVICES, CB_SETCURSEL, 0, 0 ); + handle_wgi_devices_change( hwnd ); + + thread_stop = CreateEventW( NULL, FALSE, FALSE, NULL ); + thread = CreateThread( NULL, 0, input_thread_proc, (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_devices(); + + RoUninitialize(); + break; + } + return TRUE; + + case WM_USER: + return TRUE; + } + + return FALSE; +}
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/joy.cpl/wginput.c | 178 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 162 insertions(+), 16 deletions(-)
diff --git a/dlls/joy.cpl/wginput.c b/dlls/joy.cpl/wginput.c index e033d021fe5..89dfaac5aa6 100644 --- a/dlls/joy.cpl/wginput.c +++ b/dlls/joy.cpl/wginput.c @@ -43,6 +43,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(joycpl);
+struct iface +{ + struct list entry; + IGameController *iface; +}; + struct device { struct list entry; @@ -59,41 +65,54 @@ static CRITICAL_SECTION_DEBUG state_cs_debug = static CRITICAL_SECTION state_cs = { &state_cs_debug, -1, 0, 0, 0, 0 };
static struct list devices = LIST_INIT( devices ); -static IRawGameController *device_selected; +static struct list ifaces = LIST_INIT( ifaces ); +static IGameController *iface_selected;
static HWND dialog_hwnd; static HANDLE state_event;
-static void set_selected_device( IRawGameController *device ) +static void set_selected_interface( IGameController *iface ) { - IRawGameController *previous; + IGameController *previous;
EnterCriticalSection( &state_cs );
- if ((previous = device_selected)) IRawGameController_Release( previous ); - if ((device_selected = device)) IRawGameController_AddRef( device ); + if ((previous = iface_selected)) IGameController_Release( previous ); + if ((iface_selected = iface)) IGameController_AddRef( iface );
LeaveCriticalSection( &state_cs ); }
-static inline IRawGameController *get_selected_device(void) +static inline IGameController *get_selected_interface(void) { - IRawGameController *device; + IGameController *iface;
EnterCriticalSection( &state_cs ); - device = device_selected; - if (device) IRawGameController_AddRef( device ); + iface = iface_selected; + if (iface) IGameController_AddRef( iface ); LeaveCriticalSection( &state_cs );
- return device; + return iface; +} + +static void clear_interfaces(void) +{ + struct iface *entry, *next; + + set_selected_interface( NULL ); + + LIST_FOR_EACH_ENTRY_SAFE( entry, next, &ifaces, struct iface, entry ) + { + list_remove( &entry->entry ); + IGameController_Release( entry->iface ); + free( entry ); + } }
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 ); @@ -113,14 +132,133 @@ static DWORD WINAPI input_thread_proc( void *param ) return 0; }
+static void handle_wgi_interface_change( HWND hwnd ) +{ + IGameController *iface; + struct list *entry; + int i; + + set_selected_interface( NULL ); + + i = SendDlgItemMessageW( hwnd, IDC_WGI_INTERFACE, CB_GETCURSEL, 0, 0 ); + if (i < 0) return; + + entry = list_head( &ifaces ); + while (i-- && entry) entry = list_next( &ifaces, entry ); + if (!entry) return; + + iface = LIST_ENTRY( entry, struct iface, entry )->iface; + set_selected_interface( iface ); +} + +static HRESULT check_gamepad_interface( IRawGameController *device, IGameController **iface ) +{ + const WCHAR *class_name = RuntimeClass_Windows_Gaming_Input_Gamepad; + IGameController *controller; + IGamepadStatics2 *statics; + IGamepad *gamepad = NULL; + HSTRING str; + + WindowsCreateString( class_name, wcslen( class_name ), &str ); + RoGetActivationFactory( str, &IID_IGamepadStatics2, (void **)&statics ); + WindowsDeleteString( str ); + if (!statics) return E_NOINTERFACE; + + if (SUCCEEDED(IRawGameController_QueryInterface( device, &IID_IGameController, (void **)&controller ))) + { + IGamepadStatics2_FromGameController( statics, controller, &gamepad ); + IGameController_Release( controller ); + } + + IGamepadStatics2_Release( statics ); + if (!gamepad) return E_NOINTERFACE; + + IGamepad_QueryInterface( gamepad, &IID_IGameController, (void **)iface ); + IGamepad_Release( gamepad ); + return S_OK; +} + +static HRESULT check_racing_wheel_interface( IRawGameController *device, IGameController **iface ) +{ + const WCHAR *class_name = RuntimeClass_Windows_Gaming_Input_RacingWheel; + IRacingWheelStatics2 *statics; + IGameController *controller; + IRacingWheel *wheel = NULL; + HSTRING str; + + WindowsCreateString( class_name, wcslen( class_name ), &str ); + RoGetActivationFactory( str, &IID_IRacingWheelStatics2, (void **)&statics ); + WindowsDeleteString( str ); + if (!statics) return E_NOINTERFACE; + + if (SUCCEEDED(IRawGameController_QueryInterface( device, &IID_IGameController, (void **)&controller ))) + { + IRacingWheelStatics2_FromGameController( statics, controller, &wheel ); + IGameController_Release( controller ); + } + + IRacingWheelStatics2_Release( statics ); + if (!wheel) return E_NOINTERFACE; + + IRacingWheel_QueryInterface( wheel, &IID_IGameController, (void **)iface ); + IRacingWheel_Release( wheel ); + return S_OK; +} + +static void update_wgi_interface( HWND hwnd, IRawGameController *device ) +{ + IGameController *controller; + struct iface *iface; + + clear_interfaces(); + + if (SUCCEEDED(IRawGameController_QueryInterface( device, &IID_IGameController, + (void **)&controller ))) + { + if (!(iface = calloc( 1, sizeof(*iface)))) goto done; + list_add_tail( &ifaces, &iface->entry ); + iface->iface = controller; + } + if (SUCCEEDED(check_gamepad_interface( device, &controller ))) + { + if (!(iface = calloc( 1, sizeof(*iface)))) goto done; + list_add_tail( &ifaces, &iface->entry ); + iface->iface = controller; + } + if (SUCCEEDED(check_racing_wheel_interface( device, &controller ))) + { + if (!(iface = calloc( 1, sizeof(*iface)))) goto done; + list_add_tail( &ifaces, &iface->entry ); + iface->iface = controller; + } + controller = NULL; + + SendDlgItemMessageW( hwnd, IDC_WGI_INTERFACE, CB_RESETCONTENT, 0, 0 ); + + LIST_FOR_EACH_ENTRY( iface, &ifaces, struct iface, entry ) + { + HSTRING name; + + if (FAILED(IGameController_GetRuntimeClassName( iface->iface, &name ))) continue; + + SendDlgItemMessageW( hwnd, IDC_WGI_INTERFACE, CB_ADDSTRING, 0, + (LPARAM)(wcsrchr( WindowsGetStringRawBuffer( name, NULL ), '.' ) + 1) ); + + WindowsDeleteString( name ); + } + +done: + if (controller) IGameController_Release( controller ); + + SendDlgItemMessageW( hwnd, IDC_WGI_INTERFACE, CB_SETCURSEL, 0, 0 ); +} + static void handle_wgi_devices_change( HWND hwnd ) { IRawGameController *device; struct list *entry; int i;
- set_selected_device( NULL ); - i = SendDlgItemMessageW( hwnd, IDC_WGI_DEVICES, CB_GETCURSEL, 0, 0 ); if (i < 0) return;
@@ -129,7 +267,7 @@ static void handle_wgi_devices_change( HWND hwnd ) if (!entry) return;
device = LIST_ENTRY( entry, struct device, entry )->device; - set_selected_device( device ); + update_wgi_interface( hwnd, device ); }
static void update_wgi_devices( HWND hwnd ) @@ -187,7 +325,7 @@ static void update_wgi_devices( HWND hwnd ) IRawGameController_get_HardwareVendorId( entry->device, &vid ); IRawGameController_get_HardwareProductId( entry->device, &pid );
- swprintf( buffer, ARRAY_SIZE(buffer), L"RawGameController %04x:%04x", vid, pid ); + swprintf( buffer, ARRAY_SIZE(buffer), L"%04x:%04x", vid, pid ); SendDlgItemMessageW( hwnd, IDC_WGI_DEVICES, CB_ADDSTRING, 0, (LPARAM)buffer ); } } @@ -214,6 +352,11 @@ extern INT_PTR CALLBACK test_wgi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam { case MAKEWPARAM( IDC_WGI_DEVICES, CBN_SELCHANGE ): handle_wgi_devices_change( hwnd ); + handle_wgi_interface_change( hwnd ); + break; + + case MAKEWPARAM( IDC_WGI_INTERFACE, CBN_SELCHANGE ): + handle_wgi_interface_change( hwnd ); break; } return TRUE; @@ -234,6 +377,9 @@ extern INT_PTR CALLBACK test_wgi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam SendDlgItemMessageW( hwnd, IDC_WGI_DEVICES, CB_SETCURSEL, 0, 0 ); handle_wgi_devices_change( hwnd );
+ SendDlgItemMessageW( hwnd, IDC_WGI_INTERFACE, CB_SETCURSEL, 0, 0 ); + handle_wgi_interface_change( hwnd ); + thread_stop = CreateEventW( NULL, FALSE, FALSE, NULL ); thread = CreateThread( NULL, 0, input_thread_proc, (void *)thread_stop, 0, NULL ); break;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/joy.cpl/wginput.c | 74 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+)
diff --git a/dlls/joy.cpl/wginput.c b/dlls/joy.cpl/wginput.c index 89dfaac5aa6..d7d4fde8594 100644 --- a/dlls/joy.cpl/wginput.c +++ b/dlls/joy.cpl/wginput.c @@ -55,6 +55,24 @@ struct device IRawGameController *device; };
+struct raw_controller_state +{ + UINT64 timestamp; + double axes[6]; + boolean buttons[32]; + GameControllerSwitchPosition switches[4]; +}; + +struct device_state +{ + const GUID *iid; + union + { + struct raw_controller_state raw_controller; + GamepadReading gamepad; + }; +}; + static CRITICAL_SECTION state_cs; static CRITICAL_SECTION_DEBUG state_cs_debug = { @@ -64,6 +82,7 @@ static CRITICAL_SECTION_DEBUG state_cs_debug = }; static CRITICAL_SECTION state_cs = { &state_cs_debug, -1, 0, 0, 0, 0 };
+static struct device_state device_state; static struct list devices = LIST_INIT( devices ); static struct list ifaces = LIST_INIT( ifaces ); static IGameController *iface_selected; @@ -71,6 +90,25 @@ static IGameController *iface_selected; static HWND dialog_hwnd; static HANDLE state_event;
+static void set_device_state( struct device_state *state ) +{ + BOOL modified; + + EnterCriticalSection( &state_cs ); + modified = memcmp( &device_state, state, sizeof(*state) ); + device_state = *state; + LeaveCriticalSection( &state_cs ); + + if (modified) SendMessageW( dialog_hwnd, WM_USER, 0, 0 ); +} + +static void get_device_state( struct device_state *state ) +{ + EnterCriticalSection( &state_cs ); + *state = device_state; + LeaveCriticalSection( &state_cs ); +} + static void set_selected_interface( IGameController *iface ) { IGameController *previous; @@ -123,10 +161,46 @@ static void clear_devices(void)
static DWORD WINAPI input_thread_proc( void *param ) { + union + { + struct raw_controller_state raw_controller; + GamepadReading gamepad; + } previous = {0}; + HANDLE stop_event = param;
while (WaitForSingleObject( stop_event, 20 ) == WAIT_TIMEOUT) { + IGameController *iface; + + if (!(iface = get_selected_interface())) + memset( &previous, 0, sizeof(previous) ); + else + { + IRawGameController *raw_controller; + IGamepad *gamepad; + + if (SUCCEEDED(IGameController_QueryInterface( iface, &IID_IRawGameController, (void **)&raw_controller ))) + { + struct device_state state = {.iid = &IID_IRawGameController}; + struct raw_controller_state *current = &state.raw_controller; + IRawGameController_GetCurrentReading( raw_controller, ARRAY_SIZE(current->buttons), current->buttons, + ARRAY_SIZE(current->switches), current->switches, + ARRAY_SIZE(current->axes), current->axes, ¤t->timestamp ); + IRawGameController_Release( raw_controller ); + set_device_state( &state ); + } + + if (SUCCEEDED(IGameController_QueryInterface( iface, &IID_IGamepad, (void **)&gamepad ))) + { + struct device_state state = {.iid = &IID_IGamepad}; + IGamepad_GetCurrentReading( gamepad, &state.gamepad ); + IGamepad_Release( gamepad ); + set_device_state( &state ); + } + + IGameController_Release( iface ); + } }
return 0;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/joy.cpl/joy.rc | 2 + dlls/joy.cpl/joy_private.h | 4 ++ dlls/joy.cpl/main.c | 8 +++ dlls/joy.cpl/resource.h | 2 + dlls/joy.cpl/wginput.c | 87 ++++++++++++++++++++++++ dlls/joy.cpl/xinput.c | 134 +++++++++++++++++++------------------ 6 files changed, 172 insertions(+), 65 deletions(-)
diff --git a/dlls/joy.cpl/joy.rc b/dlls/joy.cpl/joy.rc index be6aa8bd09c..452b5abf527 100644 --- a/dlls/joy.cpl/joy.rc +++ b/dlls/joy.cpl/joy.rc @@ -107,6 +107,8 @@ FONT 8, "Ms Shell Dlg" { COMBOBOX IDC_WGI_DEVICES, 15, 10, 150, 60, CBS_DROPDOWNLIST | CBS_HASSTRINGS COMBOBOX IDC_WGI_INTERFACE, 175, 10, 131, 60, CBS_DROPDOWNLIST | CBS_HASSTRINGS + GROUPBOX "", IDC_WGI_GAMEPAD, 15, 30, 291, 60 + AUTOCHECKBOX "Rumble", IDC_WGI_RUMBLE, 260, 30, 40, 10 }
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL diff --git a/dlls/joy.cpl/joy_private.h b/dlls/joy.cpl/joy_private.h index fa320bff423..94f651e130a 100644 --- a/dlls/joy.cpl/joy_private.h +++ b/dlls/joy.cpl/joy_private.h @@ -27,9 +27,12 @@ #include "winbase.h"
#include "dinput.h" +#include "xinput.h"
#include "resource.h"
+extern void paint_gamepad_view( HWND hwnd, XINPUT_STATE *state ); + 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 ); @@ -39,5 +42,6 @@ extern INT_PTR CALLBACK test_xi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, extern LRESULT CALLBACK test_xi_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam );
extern INT_PTR CALLBACK test_wgi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); +extern LRESULT CALLBACK test_wgi_gamepad_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam );
#endif /* __JOY_PRIVATE_H */ diff --git a/dlls/joy.cpl/main.c b/dlls/joy.cpl/main.c index d6936180063..8cd51bcc5bf 100644 --- a/dlls/joy.cpl/main.c +++ b/dlls/joy.cpl/main.c @@ -518,15 +518,23 @@ static void register_window_class(void) .lpfnWndProc = &test_di_buttons_window_proc, .lpszClassName = L"JoyCplDInputButtons", }; + WNDCLASSW wgi_gamepad_class = + { + .hInstance = hcpl, + .lpfnWndProc = &test_wgi_gamepad_window_proc, + .lpszClassName = L"JoyCplWGIGamepad", + };
RegisterClassW( &xi_class ); RegisterClassW( &di_axes_class ); RegisterClassW( &di_povs_class ); RegisterClassW( &di_buttons_class ); + RegisterClassW( &wgi_gamepad_class ); }
static void unregister_window_class(void) { + UnregisterClassW( L"JoyCplWGIGamepad", hcpl ); UnregisterClassW( L"JoyCplDInputAxes", hcpl ); UnregisterClassW( L"JoyCplDInputPOVs", hcpl ); UnregisterClassW( L"JoyCplDInputButtons", hcpl ); diff --git a/dlls/joy.cpl/resource.h b/dlls/joy.cpl/resource.h index 6b4b865f182..c1782ba49b7 100644 --- a/dlls/joy.cpl/resource.h +++ b/dlls/joy.cpl/resource.h @@ -72,6 +72,8 @@
#define IDC_WGI_DEVICES 2300 #define IDC_WGI_INTERFACE 2301 +#define IDC_WGI_GAMEPAD 2302 +#define IDC_WGI_RUMBLE 2303
#define ICO_MAIN 100
diff --git a/dlls/joy.cpl/wginput.c b/dlls/joy.cpl/wginput.c index d7d4fde8594..621d38ca693 100644 --- a/dlls/joy.cpl/wginput.c +++ b/dlls/joy.cpl/wginput.c @@ -206,6 +206,50 @@ static DWORD WINAPI input_thread_proc( void *param ) return 0; }
+LRESULT CALLBACK test_wgi_gamepad_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (msg == WM_PAINT) + { + struct device_state state; + XINPUT_STATE xstate = {0}; + + get_device_state( &state ); + + xstate.Gamepad.sThumbLX = state.gamepad.LeftThumbstickX * 0x7fff; + xstate.Gamepad.sThumbLY = state.gamepad.LeftThumbstickY * 0x7fff; + if (state.gamepad.Buttons & GamepadButtons_LeftThumbstick) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; + + xstate.Gamepad.sThumbRX = state.gamepad.RightThumbstickX * 0x7fff; + xstate.Gamepad.sThumbRY = state.gamepad.RightThumbstickY * 0x7fff; + if (state.gamepad.Buttons & GamepadButtons_RightThumbstick) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; + + xstate.Gamepad.bLeftTrigger = state.gamepad.LeftTrigger * 0xff; + xstate.Gamepad.bRightTrigger = state.gamepad.RightTrigger * 0xff; + + if (state.gamepad.Buttons & GamepadButtons_DPadUp) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; + if (state.gamepad.Buttons & GamepadButtons_LeftShoulder) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; + if (state.gamepad.Buttons & GamepadButtons_RightShoulder) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; + if (state.gamepad.Buttons & GamepadButtons_Y) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_Y; + + if (state.gamepad.Buttons & GamepadButtons_DPadLeft) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; + if (state.gamepad.Buttons & GamepadButtons_DPadRight) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; + if (state.gamepad.Buttons & GamepadButtons_X) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_X; + if (state.gamepad.Buttons & GamepadButtons_B) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_B; + + if (state.gamepad.Buttons & GamepadButtons_DPadDown) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; + if (state.gamepad.Buttons & GamepadButtons_View) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_BACK; + if (state.gamepad.Buttons & GamepadButtons_Menu) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_START; + if (state.gamepad.Buttons & GamepadButtons_A) xstate.Gamepad.wButtons |= XINPUT_GAMEPAD_A; + + paint_gamepad_view( hwnd, &xstate ); + return 0; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + static void handle_wgi_interface_change( HWND hwnd ) { IGameController *iface; @@ -405,8 +449,50 @@ static void update_wgi_devices( HWND hwnd ) } }
+static void update_device_views( HWND hwnd ) +{ + HWND gamepad, rumble; + struct device_state state; + + get_device_state( &state ); + + gamepad = GetDlgItem( hwnd, IDC_WGI_GAMEPAD ); + rumble = GetDlgItem( hwnd, IDC_WGI_RUMBLE ); + + if (!IsEqualGUID( state.iid, &IID_IGamepad )) + { + ShowWindow( gamepad, SW_HIDE ); + ShowWindow( rumble, SW_HIDE ); + } + else + { + InvalidateRect( gamepad, NULL, TRUE ); + InvalidateRect( rumble, NULL, TRUE ); + ShowWindow( gamepad, SW_SHOW ); + ShowWindow( rumble, SW_SHOW ); + } +} + static void create_device_views( HWND hwnd ) { + HINSTANCE instance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ); + HWND gamepad, rumble; + LONG margin; + RECT rect; + + gamepad = GetDlgItem( hwnd, IDC_WGI_GAMEPAD ); + rumble = GetDlgItem( hwnd, IDC_WGI_RUMBLE ); + ShowWindow( gamepad, SW_HIDE ); + ShowWindow( rumble, SW_HIDE ); + + GetClientRect( gamepad, &rect ); + rect.top += 10; + + margin = (rect.bottom - rect.top) * 15 / 100; + InflateRect( &rect, -margin, -margin ); + + CreateWindowW( L"JoyCplWGIGamepad", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, gamepad, NULL, NULL, instance ); }
extern INT_PTR CALLBACK test_wgi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) @@ -474,6 +560,7 @@ extern INT_PTR CALLBACK test_wgi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam return TRUE;
case WM_USER: + update_device_views( hwnd ); return TRUE; }
diff --git a/dlls/joy.cpl/xinput.c b/dlls/joy.cpl/xinput.c index 2285485ae44..977c3ecd2d6 100644 --- a/dlls/joy.cpl/xinput.c +++ b/dlls/joy.cpl/xinput.c @@ -247,6 +247,74 @@ static void draw_button_view( HDC hdc, RECT rect, BOOL set, const WCHAR *name ) SelectObject( hdc, font ); }
+void paint_gamepad_view( HWND hwnd, XINPUT_STATE *state ) +{ + UINT axis_size, trigger_size, button_size, horiz_space; + RECT rect, tmp_rect; + PAINTSTRUCT paint; + HDC hdc; + + GetClientRect( hwnd, &rect ); + axis_size = rect.bottom - rect.top; + button_size = (axis_size - 1) / 3; + trigger_size = axis_size / 4; + horiz_space = (rect.right - rect.left - axis_size * 2 - trigger_size * 2 - button_size * 5) / 10; + + hdc = BeginPaint( hwnd, &paint ); + + rect.right = rect.left + axis_size; + OffsetRect( &rect, horiz_space, 0 ); + draw_axis_view( hdc, rect, state->Gamepad.sThumbLX, state->Gamepad.sThumbLY, + state->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_axis_view( hdc, rect, state->Gamepad.sThumbRX, state->Gamepad.sThumbRY, + state->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ); + + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + rect.right = rect.left + trigger_size; + draw_trigger_view( hdc, rect, state->Gamepad.bLeftTrigger ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_trigger_view( hdc, rect, state->Gamepad.bRightTrigger ); + + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + rect.right = rect.left + button_size; + rect.bottom = rect.top + button_size; + tmp_rect = rect; + OffsetRect( &rect, (rect.right - rect.left + horiz_space) / 2, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP, L"^" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER, L"L" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER, L"R" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_Y, L"Y" ); + + rect = tmp_rect; + OffsetRect( &rect, 0, rect.bottom - rect.top ); + tmp_rect = rect; + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT, L"<" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT, L">" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & 0x0400, L"@" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_X, L"X" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_B, L"B" ); + + rect = tmp_rect; + OffsetRect( &rect, (rect.right - rect.left + horiz_space) / 2, rect.bottom - rect.top ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN, L"v" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_BACK, L"#" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_START, L"=" ); + OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); + draw_button_view( hdc, rect, state->Gamepad.wButtons & XINPUT_GAMEPAD_A, L"A" ); + + EndPaint( hwnd, &paint ); +} + LRESULT CALLBACK test_xi_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); @@ -254,74 +322,10 @@ LRESULT CALLBACK test_xi_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM if (msg == WM_PAINT) { DWORD index = GetWindowLongW( hwnd, GWLP_USERDATA ); - UINT axis_size, trigger_size, button_size, horiz_space; struct device_state state; - RECT rect, tmp_rect; - PAINTSTRUCT paint; - HDC hdc; - - GetClientRect( hwnd, &rect ); - axis_size = rect.bottom - rect.top; - button_size = (axis_size - 1) / 3; - trigger_size = axis_size / 4; - horiz_space = (rect.right - rect.left - axis_size * 2 - trigger_size * 2 - button_size * 5) / 10;
get_device_state( index, &state ); - - hdc = BeginPaint( hwnd, &paint ); - - rect.right = rect.left + axis_size; - OffsetRect( &rect, horiz_space, 0 ); - draw_axis_view( hdc, rect, state.state.Gamepad.sThumbLX, state.state.Gamepad.sThumbLY, - state.state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_axis_view( hdc, rect, state.state.Gamepad.sThumbRX, state.state.Gamepad.sThumbRY, - state.state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ); - - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - rect.right = rect.left + trigger_size; - draw_trigger_view( hdc, rect, state.state.Gamepad.bLeftTrigger ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_trigger_view( hdc, rect, state.state.Gamepad.bRightTrigger ); - - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - rect.right = rect.left + button_size; - rect.bottom = rect.top + button_size; - tmp_rect = rect; - OffsetRect( &rect, (rect.right - rect.left + horiz_space) / 2, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP, L"^" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER, L"L" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER, L"R" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_Y, L"Y" ); - - rect = tmp_rect; - OffsetRect( &rect, 0, rect.bottom - rect.top ); - tmp_rect = rect; - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT, L"<" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT, L">" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & 0x0400, L"@" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_X, L"X" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_B, L"B" ); - - rect = tmp_rect; - OffsetRect( &rect, (rect.right - rect.left + horiz_space) / 2, rect.bottom - rect.top ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN, L"v" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK, L"#" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_START, L"=" ); - OffsetRect( &rect, rect.right - rect.left + horiz_space, 0 ); - draw_button_view( hdc, rect, state.state.Gamepad.wButtons & XINPUT_GAMEPAD_A, L"A" ); - - EndPaint( hwnd, &paint ); - + paint_gamepad_view( hwnd, &state.state ); return 0; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/joy.cpl/dinput.c | 227 ++++++++++++++++++++----------------- dlls/joy.cpl/joy.rc | 3 + dlls/joy.cpl/joy_private.h | 6 + dlls/joy.cpl/main.c | 24 ++++ dlls/joy.cpl/resource.h | 3 + dlls/joy.cpl/wginput.c | 137 +++++++++++++++++++++- 6 files changed, 297 insertions(+), 103 deletions(-)
diff --git a/dlls/joy.cpl/dinput.c b/dlls/joy.cpl/dinput.c index a536fd167a1..bf5ef22edcb 100644 --- a/dlls/joy.cpl/dinput.c +++ b/dlls/joy.cpl/dinput.c @@ -309,7 +309,7 @@ static DWORD WINAPI input_thread( void *param ) return 0; }
-static void draw_axis_view( HDC hdc, RECT rect, const WCHAR *name, LONG value ) +static void draw_axis_view( HDC hdc, RECT rect, const WCHAR *name, double value ) { POINT center = { @@ -317,7 +317,7 @@ static void draw_axis_view( HDC hdc, RECT rect, const WCHAR *name, LONG value ) .y = (rect.top + rect.bottom) / 2, }; LONG w = (rect.bottom - rect.top + 1) / 3; - LONG x = rect.left + 20 + (w + 1) / 2 + MulDiv( value, rect.right - rect.left - 20 - w, 0xffff ); + LONG x = rect.left + 20 + (w + 1) / 2 + value * (rect.right - rect.left - 20 - w); COLORREF color; HFONT font;
@@ -354,6 +354,53 @@ static void draw_axis_view( HDC hdc, RECT rect, const WCHAR *name, LONG value ) } }
+void paint_axes_view( HWND hwnd, UINT32 count, double *axes ) +{ + RECT rect, tmp_rect; + PAINTSTRUCT paint; + HDC hdc; + + hdc = BeginPaint( hwnd, &paint ); + + GetClientRect( hwnd, &rect ); + rect.bottom = rect.top + (rect.bottom - rect.top - 2) / 4 - 2; + rect.right = rect.left + (rect.right - rect.left) / 2 - 10; + + OffsetRect( &rect, 5, 2 ); + draw_axis_view( hdc, rect, L"X", axes[0] ); + + tmp_rect = rect; + OffsetRect( &rect, rect.right - rect.left + 10, 0 ); + draw_axis_view( hdc, rect, L"Rx", axes[1] ); + rect = tmp_rect; + + OffsetRect( &rect, 0, rect.bottom - rect.top + 2 ); + draw_axis_view( hdc, rect, L"Y", axes[2] ); + + tmp_rect = rect; + OffsetRect( &rect, rect.right - rect.left + 10, 0 ); + draw_axis_view( hdc, rect, L"Ry", axes[3] ); + rect = tmp_rect; + + OffsetRect( &rect, 0, rect.bottom - rect.top + 2 ); + draw_axis_view( hdc, rect, L"Z", axes[4] ); + + tmp_rect = rect; + OffsetRect( &rect, rect.right - rect.left + 10, 0 ); + draw_axis_view( hdc, rect, L"Rz", axes[5] ); + rect = tmp_rect; + + OffsetRect( &rect, 0, rect.bottom - rect.top + 2 ); + draw_axis_view( hdc, rect, L"S", axes[6] ); + + tmp_rect = rect; + OffsetRect( &rect, rect.right - rect.left + 10, 0 ); + draw_axis_view( hdc, rect, L"Rs", axes[7] ); + rect = tmp_rect; + + EndPaint( hwnd, &paint ); +} + static void draw_pov_view( HDC hdc, RECT rect, DWORD value ) { POINT points[] = @@ -407,6 +454,30 @@ static void draw_pov_view( HDC hdc, RECT rect, DWORD value ) if (value != -1) Polygon( hdc, points + value / 4500 * 2, 3 ); }
+void paint_povs_view( HWND hwnd, UINT32 count, UINT32 *povs ) +{ + PAINTSTRUCT paint; + RECT rect; + HDC hdc; + + hdc = BeginPaint( hwnd, &paint ); + + GetClientRect( hwnd, &rect ); + rect.bottom = rect.top + (rect.bottom - rect.top - 5) / 2 - 5; + rect.right = rect.left + (rect.bottom - rect.top); + + OffsetRect( &rect, 5, 5 ); + draw_pov_view( hdc, rect, povs[0] ); + OffsetRect( &rect, rect.right - rect.left + 5, 0 ); + draw_pov_view( hdc, rect, povs[1] ); + OffsetRect( &rect, rect.left - rect.right - 5, rect.bottom - rect.top + 5 ); + draw_pov_view( hdc, rect, povs[1] ); + OffsetRect( &rect, rect.right - rect.left + 5, 0 ); + draw_pov_view( hdc, rect, povs[2] ); + + EndPaint( hwnd, &paint ); +} + static void draw_button_view( HDC hdc, RECT rect, BOOL set, const WCHAR *name ) { COLORREF color; @@ -432,6 +503,47 @@ static void draw_button_view( HDC hdc, RECT rect, BOOL set, const WCHAR *name ) SelectObject( hdc, font ); }
+void paint_buttons_view( HWND hwnd, UINT32 count, BYTE *buttons ) +{ + UINT i, j, offs, size, step, space = 2; + PAINTSTRUCT paint; + RECT rect; + HDC hdc; + + if (count <= 48) step = 16; + else step = 24; + + hdc = BeginPaint( hwnd, &paint ); + + GetClientRect( hwnd, &rect ); + FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); + + size = (rect.right - rect.left - space) / step; + offs = (rect.right - rect.left - step * size - space) / 2; + OffsetRect( &rect, offs, offs ); + rect.right = rect.left + size - space; + rect.bottom = rect.top + size - space; + + for (i = 0; i < count;) + { + RECT first = rect; + + for (j = 0; j < step && i < count; j++, i++) + { + WCHAR buffer[3]; + if (step == 24) swprintf( buffer, ARRAY_SIZE(buffer), L"%02x", i ); + else swprintf( buffer, ARRAY_SIZE(buffer), L"%d", i ); + draw_button_view( hdc, rect, buttons[i], buffer ); + OffsetRect( &rect, size, 0 ); + } + + rect = first; + OffsetRect( &rect, 0, size ); + } + + EndPaint( hwnd, &paint ); +} + LRESULT CALLBACK test_di_axes_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); @@ -439,11 +551,9 @@ LRESULT CALLBACK test_di_axes_window_proc( HWND hwnd, UINT msg, WPARAM wparam, L if (msg == WM_PAINT) { DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; + double axes[16], *axis = axes; IDirectInputDevice8W *device; DIJOYSTATE2 state = {0}; - RECT rect, tmp_rect; - PAINTSTRUCT paint; - HDC hdc;
if ((device = get_selected_device())) { @@ -452,46 +562,16 @@ LRESULT CALLBACK test_di_axes_window_proc( HWND hwnd, UINT msg, WPARAM wparam, L IDirectInputDevice8_Release( device ); }
- hdc = BeginPaint( hwnd, &paint ); - - GetClientRect( hwnd, &rect ); - rect.bottom = rect.top + (rect.bottom - rect.top - 2) / 4 - 2; - rect.right = rect.left + (rect.right - rect.left) / 2 - 10; - - OffsetRect( &rect, 5, 2 ); - draw_axis_view( hdc, rect, L"X", state.lX ); - - tmp_rect = rect; - OffsetRect( &rect, rect.right - rect.left + 10, 0 ); - draw_axis_view( hdc, rect, L"Rx", state.lRx ); - rect = tmp_rect; - - OffsetRect( &rect, 0, rect.bottom - rect.top + 2 ); - draw_axis_view( hdc, rect, L"Y", state.lY ); - - tmp_rect = rect; - OffsetRect( &rect, rect.right - rect.left + 10, 0 ); - draw_axis_view( hdc, rect, L"Ry", state.lRy ); - rect = tmp_rect; - - OffsetRect( &rect, 0, rect.bottom - rect.top + 2 ); - draw_axis_view( hdc, rect, L"Z", state.lZ ); - - tmp_rect = rect; - OffsetRect( &rect, rect.right - rect.left + 10, 0 ); - draw_axis_view( hdc, rect, L"Rz", state.lRz ); - rect = tmp_rect; - - OffsetRect( &rect, 0, rect.bottom - rect.top + 2 ); - draw_axis_view( hdc, rect, L"S", state.rglSlider[0] ); - - tmp_rect = rect; - OffsetRect( &rect, rect.right - rect.left + 10, 0 ); - draw_axis_view( hdc, rect, L"Rs", state.rglSlider[1] ); - rect = tmp_rect; - - EndPaint( hwnd, &paint ); + *axis++ = (double)state.lX / 65535.; + *axis++ = (double)state.lRx / 65535.; + *axis++ = (double)state.lY / 65535.; + *axis++ = (double)state.lRy / 65535.; + *axis++ = (double)state.lZ / 65535.; + *axis++ = (double)state.lRz / 65535.; + *axis++ = (double)state.rglSlider[0] / 65535.; + *axis++ = (double)state.rglSlider[1] / 65535.;
+ paint_axes_view( hwnd, min( caps.dwAxes, ARRAY_SIZE(axes) ), axes ); return 0; }
@@ -507,9 +587,6 @@ LRESULT CALLBACK test_di_povs_window_proc( HWND hwnd, UINT msg, WPARAM wparam, L DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; IDirectInputDevice8W *device; DIJOYSTATE2 state = {0}; - PAINTSTRUCT paint; - RECT rect; - HDC hdc;
if ((device = get_selected_device())) { @@ -518,23 +595,7 @@ LRESULT CALLBACK test_di_povs_window_proc( HWND hwnd, UINT msg, WPARAM wparam, L IDirectInputDevice8_Release( device ); }
- hdc = BeginPaint( hwnd, &paint ); - - GetClientRect( hwnd, &rect ); - rect.bottom = rect.top + (rect.bottom - rect.top - 5) / 2 - 5; - rect.right = rect.left + (rect.bottom - rect.top); - - OffsetRect( &rect, 5, 5 ); - draw_pov_view( hdc, rect, state.rgdwPOV[0] ); - OffsetRect( &rect, rect.right - rect.left + 5, 0 ); - draw_pov_view( hdc, rect, state.rgdwPOV[1] ); - OffsetRect( &rect, rect.left - rect.right - 5, rect.bottom - rect.top + 5 ); - draw_pov_view( hdc, rect, state.rgdwPOV[1] ); - OffsetRect( &rect, rect.right - rect.left + 5, 0 ); - draw_pov_view( hdc, rect, state.rgdwPOV[2] ); - - EndPaint( hwnd, &paint ); - + paint_povs_view( hwnd, caps.dwPOVs, (UINT32 *)state.rgdwPOV ); return 0; }
@@ -548,12 +609,8 @@ 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; DIJOYSTATE2 state = {0}; - PAINTSTRUCT paint; - RECT rect; - HDC hdc;
if ((device = get_selected_device())) { @@ -562,39 +619,7 @@ LRESULT CALLBACK test_di_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam IDirectInputDevice8_Release( device ); }
- if (caps.dwButtons <= 48) step = 16; - else step = 24; - - hdc = BeginPaint( hwnd, &paint ); - - GetClientRect( hwnd, &rect ); - FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); - - size = (rect.right - rect.left - space) / step; - offs = (rect.right - rect.left - step * size - space) / 2; - OffsetRect( &rect, offs, offs ); - rect.right = rect.left + size - space; - rect.bottom = rect.top + size - space; - - for (i = 0; i < ARRAY_SIZE(state.rgbButtons) && i < caps.dwButtons;) - { - RECT first = rect; - - for (j = 0; j < step && i < caps.dwButtons; j++, i++) - { - WCHAR buffer[3]; - if (step == 24) swprintf( buffer, ARRAY_SIZE(buffer), L"%02x", i ); - else swprintf( buffer, ARRAY_SIZE(buffer), L"%d", i ); - draw_button_view( hdc, rect, state.rgbButtons[i], buffer ); - OffsetRect( &rect, size, 0 ); - } - - rect = first; - OffsetRect( &rect, 0, size ); - } - - EndPaint( hwnd, &paint ); - + paint_buttons_view( hwnd, min( caps.dwButtons, ARRAY_SIZE(state.rgbButtons) ), state.rgbButtons ); return 0; }
diff --git a/dlls/joy.cpl/joy.rc b/dlls/joy.cpl/joy.rc index 452b5abf527..1eb62d86ab3 100644 --- a/dlls/joy.cpl/joy.rc +++ b/dlls/joy.cpl/joy.rc @@ -107,6 +107,9 @@ FONT 8, "Ms Shell Dlg" { COMBOBOX IDC_WGI_DEVICES, 15, 10, 150, 60, CBS_DROPDOWNLIST | CBS_HASSTRINGS COMBOBOX IDC_WGI_INTERFACE, 175, 10, 131, 60, CBS_DROPDOWNLIST | CBS_HASSTRINGS + GROUPBOX "Axes", IDC_WGI_AXES, 15, 30, 214, 60 + GROUPBOX "POVs", IDC_WGI_POVS, 246, 30, 60, 60 + GROUPBOX "Buttons", IDC_WGI_BUTTONS, 15, 100, 291, 86 GROUPBOX "", IDC_WGI_GAMEPAD, 15, 30, 291, 60 AUTOCHECKBOX "Rumble", IDC_WGI_RUMBLE, 260, 30, 40, 10 } diff --git a/dlls/joy.cpl/joy_private.h b/dlls/joy.cpl/joy_private.h index 94f651e130a..135d76753c6 100644 --- a/dlls/joy.cpl/joy_private.h +++ b/dlls/joy.cpl/joy_private.h @@ -31,6 +31,9 @@
#include "resource.h"
+extern void paint_axes_view( HWND hwnd, UINT32 count, double *axes ); +extern void paint_povs_view( HWND hwnd, UINT32 count, UINT32 *povs ); +extern void paint_buttons_view( HWND hwnd, UINT32 count, BYTE *buttons ); extern void paint_gamepad_view( HWND hwnd, XINPUT_STATE *state );
extern INT_PTR CALLBACK test_di_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); @@ -42,6 +45,9 @@ extern INT_PTR CALLBACK test_xi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, extern LRESULT CALLBACK test_xi_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam );
extern INT_PTR CALLBACK test_wgi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); +extern LRESULT CALLBACK test_wgi_axes_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); +extern LRESULT CALLBACK test_wgi_povs_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); +extern LRESULT CALLBACK test_wgi_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); extern LRESULT CALLBACK test_wgi_gamepad_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam );
#endif /* __JOY_PRIVATE_H */ diff --git a/dlls/joy.cpl/main.c b/dlls/joy.cpl/main.c index 8cd51bcc5bf..d667ae6b5b0 100644 --- a/dlls/joy.cpl/main.c +++ b/dlls/joy.cpl/main.c @@ -518,6 +518,24 @@ static void register_window_class(void) .lpfnWndProc = &test_di_buttons_window_proc, .lpszClassName = L"JoyCplDInputButtons", }; + WNDCLASSW wgi_axes_class = + { + .hInstance = hcpl, + .lpfnWndProc = &test_wgi_axes_window_proc, + .lpszClassName = L"JoyCplWGIAxes", + }; + WNDCLASSW wgi_povs_class = + { + .hInstance = hcpl, + .lpfnWndProc = &test_wgi_povs_window_proc, + .lpszClassName = L"JoyCplWGIPOVs", + }; + WNDCLASSW wgi_buttons_class = + { + .hInstance = hcpl, + .lpfnWndProc = &test_wgi_buttons_window_proc, + .lpszClassName = L"JoyCplWGIButtons", + }; WNDCLASSW wgi_gamepad_class = { .hInstance = hcpl, @@ -529,11 +547,17 @@ static void register_window_class(void) RegisterClassW( &di_axes_class ); RegisterClassW( &di_povs_class ); RegisterClassW( &di_buttons_class ); + RegisterClassW( &wgi_axes_class ); + RegisterClassW( &wgi_povs_class ); + RegisterClassW( &wgi_buttons_class ); RegisterClassW( &wgi_gamepad_class ); }
static void unregister_window_class(void) { + UnregisterClassW( L"JoyCplWGIAxes", hcpl ); + UnregisterClassW( L"JoyCplWGIPovs", hcpl ); + UnregisterClassW( L"JoyCplWGIButtons", hcpl ); UnregisterClassW( L"JoyCplWGIGamepad", hcpl ); UnregisterClassW( L"JoyCplDInputAxes", hcpl ); UnregisterClassW( L"JoyCplDInputPOVs", hcpl ); diff --git a/dlls/joy.cpl/resource.h b/dlls/joy.cpl/resource.h index c1782ba49b7..894fa016b66 100644 --- a/dlls/joy.cpl/resource.h +++ b/dlls/joy.cpl/resource.h @@ -74,6 +74,9 @@ #define IDC_WGI_INTERFACE 2301 #define IDC_WGI_GAMEPAD 2302 #define IDC_WGI_RUMBLE 2303 +#define IDC_WGI_AXES 2304 +#define IDC_WGI_POVS 2305 +#define IDC_WGI_BUTTONS 2306
#define ICO_MAIN 100
diff --git a/dlls/joy.cpl/wginput.c b/dlls/joy.cpl/wginput.c index 621d38ca693..67e546537ca 100644 --- a/dlls/joy.cpl/wginput.c +++ b/dlls/joy.cpl/wginput.c @@ -59,8 +59,11 @@ struct raw_controller_state { UINT64 timestamp; double axes[6]; + INT32 axes_count; boolean buttons[32]; + INT32 button_count; GameControllerSwitchPosition switches[4]; + INT32 switches_count; };
struct device_state @@ -184,6 +187,9 @@ static DWORD WINAPI input_thread_proc( void *param ) { struct device_state state = {.iid = &IID_IRawGameController}; struct raw_controller_state *current = &state.raw_controller; + IRawGameController_get_AxisCount( raw_controller, ¤t->axes_count ); + IRawGameController_get_ButtonCount( raw_controller, ¤t->button_count ); + IRawGameController_get_SwitchCount( raw_controller, ¤t->switches_count ); IRawGameController_GetCurrentReading( raw_controller, ARRAY_SIZE(current->buttons), current->buttons, ARRAY_SIZE(current->switches), current->switches, ARRAY_SIZE(current->axes), current->axes, ¤t->timestamp ); @@ -206,6 +212,80 @@ static DWORD WINAPI input_thread_proc( void *param ) return 0; }
+LRESULT CALLBACK test_wgi_axes_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (msg == WM_PAINT) + { + struct device_state state; + UINT32 count; + + get_device_state( &state ); + + count = min( state.raw_controller.axes_count, ARRAY_SIZE(state.raw_controller.axes) ); + paint_axes_view( hwnd, count, state.raw_controller.axes ); + return 0; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +LRESULT CALLBACK test_wgi_povs_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (msg == WM_PAINT) + { + struct device_state state; + UINT32 count, povs[ARRAY_SIZE(state.raw_controller.switches)]; + + get_device_state( &state ); + + for (int i = 0; i < ARRAY_SIZE(state.raw_controller.switches); i++) + { + if (i >= state.raw_controller.switches_count) povs[i] = -1; + else switch (state.raw_controller.switches[i]) + { + case GameControllerSwitchPosition_Center: povs[i] = -1; break; + case GameControllerSwitchPosition_Up: povs[i] = 0; break; + case GameControllerSwitchPosition_UpRight: povs[i] = 4500; break; + case GameControllerSwitchPosition_Right: povs[i] = 9000; break; + case GameControllerSwitchPosition_DownRight: povs[i] = 13500; break; + case GameControllerSwitchPosition_Down: povs[i] = 18000; break; + case GameControllerSwitchPosition_DownLeft: povs[i] = 22500; break; + case GameControllerSwitchPosition_Left: povs[i] = 27000; break; + case GameControllerSwitchPosition_UpLeft: povs[i] = 31500; break; + } + } + + count = min( state.raw_controller.switches_count, ARRAY_SIZE(povs) ); + paint_povs_view( hwnd, count, povs ); + return 0; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +LRESULT CALLBACK test_wgi_buttons_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); + + if (msg == WM_PAINT) + { + struct device_state state; + UINT32 count; + + get_device_state( &state ); + + count = min( state.raw_controller.button_count, ARRAY_SIZE(state.raw_controller.buttons) ); + paint_buttons_view( hwnd, count, state.raw_controller.buttons ); + return 0; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + LRESULT CALLBACK test_wgi_gamepad_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd, msg, wparam, lparam ); @@ -451,13 +531,32 @@ static void update_wgi_devices( HWND hwnd )
static void update_device_views( HWND hwnd ) { - HWND gamepad, rumble; + HWND gamepad, rumble, axes, povs, buttons; struct device_state state;
get_device_state( &state );
gamepad = GetDlgItem( hwnd, IDC_WGI_GAMEPAD ); rumble = GetDlgItem( hwnd, IDC_WGI_RUMBLE ); + axes = GetDlgItem( hwnd, IDC_WGI_AXES ); + povs = GetDlgItem( hwnd, IDC_WGI_POVS ); + buttons = GetDlgItem( hwnd, IDC_WGI_BUTTONS ); + + if (!IsEqualGUID( state.iid, &IID_IRawGameController )) + { + ShowWindow( axes, SW_HIDE ); + ShowWindow( povs, SW_HIDE ); + ShowWindow( buttons, SW_HIDE ); + } + else + { + InvalidateRect( axes, NULL, TRUE ); + InvalidateRect( povs, NULL, TRUE ); + InvalidateRect( buttons, NULL, TRUE ); + ShowWindow( axes, SW_SHOW ); + ShowWindow( povs, SW_SHOW ); + ShowWindow( buttons, SW_SHOW ); + }
if (!IsEqualGUID( state.iid, &IID_IGamepad )) { @@ -476,14 +575,48 @@ static void update_device_views( HWND hwnd ) static void create_device_views( HWND hwnd ) { HINSTANCE instance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE ); - HWND gamepad, rumble; + HWND gamepad, rumble, axes, povs, buttons; LONG margin; RECT rect;
gamepad = GetDlgItem( hwnd, IDC_WGI_GAMEPAD ); rumble = GetDlgItem( hwnd, IDC_WGI_RUMBLE ); + axes = GetDlgItem( hwnd, IDC_WGI_AXES ); + povs = GetDlgItem( hwnd, IDC_WGI_POVS ); + buttons = GetDlgItem( hwnd, IDC_WGI_BUTTONS ); + ShowWindow( gamepad, SW_HIDE ); ShowWindow( rumble, SW_HIDE ); + ShowWindow( axes, SW_HIDE ); + ShowWindow( povs, SW_HIDE ); + ShowWindow( buttons, SW_HIDE ); + + GetClientRect( axes, &rect ); + rect.top += 10; + + margin = (rect.bottom - rect.top) * 10 / 100; + InflateRect( &rect, -margin, -margin ); + + CreateWindowW( L"JoyCplWGIAxes", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, axes, NULL, NULL, instance ); + + GetClientRect( povs, &rect ); + rect.top += 10; + + margin = (rect.bottom - rect.top) * 10 / 100; + InflateRect( &rect, -margin, -margin ); + + CreateWindowW( L"JoyCplWGIPOVs", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, povs, NULL, NULL, instance ); + + GetClientRect( buttons, &rect ); + rect.top += 10; + + margin = (rect.bottom - rect.top) * 5 / 100; + InflateRect( &rect, -margin, -margin ); + + CreateWindowW( L"JoyCplWGIButtons", NULL, WS_CHILD | WS_VISIBLE, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, buttons, NULL, NULL, instance );
GetClientRect( gamepad, &rect ); rect.top += 10;