From: Rémi Bernon rbernon@codeweavers.com
--- dlls/joy.cpl/dinput.c | 196 +++++++++++++++++++++++++++++++++++++ dlls/joy.cpl/joy.rc | 6 +- dlls/joy.cpl/joy_private.h | 2 + dlls/joy.cpl/main.c | 137 +++++++++----------------- dlls/joy.cpl/resource.h | 10 +- 5 files changed, 249 insertions(+), 102 deletions(-)
diff --git a/dlls/joy.cpl/dinput.c b/dlls/joy.cpl/dinput.c index ecec58e0fff..bf80584000e 100644 --- a/dlls/joy.cpl/dinput.c +++ b/dlls/joy.cpl/dinput.c @@ -19,6 +19,7 @@
#include <stdarg.h> #include <stddef.h> +#include <math.h>
#include "windef.h" #include "winbase.h" @@ -68,6 +69,104 @@ static void get_device_state( DIJOYSTATE *state, DIDEVCAPS *caps ) LeaveCriticalSection( &state_cs ); }
+static void draw_axis_view( HDC hdc, RECT rect, const WCHAR *name, LONG value ) +{ + POINT center = + { + .x = (rect.left + rect.right) / 2 + 10, + .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 ); + COLORREF color; + HFONT font; + + FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); + + color = SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) ); + font = SelectObject( hdc, GetStockObject( ANSI_VAR_FONT ) ); + DrawTextW( hdc, name, -1, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOCLIP ); + SetTextColor( hdc, color ); + SelectObject( hdc, font ); + + SetDCBrushColor( hdc, GetSysColor( COLOR_WINDOW ) ); + SetDCPenColor( hdc, GetSysColor( COLOR_WINDOWFRAME ) ); + SelectObject( hdc, GetStockObject( DC_BRUSH ) ); + SelectObject( hdc, GetStockObject( DC_PEN ) ); + + RoundRect( hdc, rect.left + 20, rect.top, rect.right, rect.bottom, 5, 5 ); + + if (x < center.x) + { + MoveToEx( hdc, center.x, center.y - 3, NULL ); + LineTo( hdc, center.x, center.y + 3 ); + } + + SetDCBrushColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) ); + SetDCPenColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) ); + + Rectangle( hdc, rect.left + 20, rect.top + w, x, rect.bottom - w ); + + if (x > center.x) + { + MoveToEx( hdc, center.x, center.y - 3, NULL ); + LineTo( hdc, center.x, center.y + 3 ); + } +} + +static void draw_pov_view( HDC hdc, RECT rect, DWORD value ) +{ + POINT points[] = + { + /* 0° */ + {.x = round( rect.left * 0.71 + rect.right * 0.29 ), .y = round( rect.top * 1.00 + rect.bottom * 0.00 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + /* 45° */ + {.x = round( rect.left * 0.29 + rect.right * 0.71 ), .y = round( rect.top * 1.00 + rect.bottom * 0.00 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + /* 90° */ + {.x = round( rect.left * 0.00 + rect.right * 1.00 ), .y = round( rect.top * 0.71 + rect.bottom * 0.29 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + /* 135° */ + {.x = round( rect.left * 0.00 + rect.right * 1.00 ), .y = round( rect.top * 0.29 + rect.bottom * 0.71 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + /* 180° */ + {.x = round( rect.left * 0.29 + rect.right * 0.71 ), .y = round( rect.top * 0.00 + rect.bottom * 1.00 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + /* 225° */ + {.x = round( rect.left * 0.71 + rect.right * 0.29 ), .y = round( rect.top * 0.00 + rect.bottom * 1.00 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + /* 270° */ + {.x = round( rect.left * 1.00 + rect.right * 0.00 ), .y = round( rect.top * 0.29 + rect.bottom * 0.71 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + /* 315° */ + {.x = round( rect.left * 1.00 + rect.right * 0.00 ), .y = round( rect.top * 0.71 + rect.bottom * 0.29 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + /* 360° */ + {.x = round( rect.left * 0.71 + rect.right * 0.29 ), .y = round( rect.top * 1.00 + rect.bottom * 0.00 )}, + {.x = round( rect.left * 0.50 + rect.right * 0.50 ), .y = round( rect.top * 0.50 + rect.bottom * 0.50 )}, + {.x = round( rect.left * 0.71 + rect.right * 0.29 ), .y = round( rect.top * 1.00 + rect.bottom * 0.00 )}, + }; + DWORD i; + + FillRect( hdc, &rect, (HBRUSH)(COLOR_WINDOW + 1) ); + + SetDCBrushColor( hdc, GetSysColor( COLOR_WINDOW ) ); + SetDCPenColor( hdc, GetSysColor( COLOR_WINDOWFRAME ) ); + SelectObject( hdc, GetStockObject( DC_BRUSH ) ); + SelectObject( hdc, GetStockObject( DC_PEN ) ); + + for (i = 0; i < ARRAY_SIZE(points) - 1; i += 2) + { + MoveToEx( hdc, (points[i].x + points[i + 1].x) / 2, (points[i].y + points[i + 1].y) / 2, NULL ); + LineTo( hdc, points[i].x, points[i].y ); + } + + SetDCPenColor( hdc, GetSysColor( (value != -1) ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWFRAME ) ); + SetDCBrushColor( hdc, GetSysColor( (value != -1) ? COLOR_HIGHLIGHT : COLOR_WINDOW ) ); + 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 ) { COLORREF color; @@ -92,6 +191,103 @@ static inline void draw_button_view( HDC hdc, RECT rect, BOOL set, const WCHAR * SelectObject( hdc, font ); }
+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 ); + + if (msg == WM_PAINT) + { + RECT rect, tmp_rect; + PAINTSTRUCT paint; + DIJOYSTATE state; + DIDEVCAPS caps; + HDC hdc; + + get_device_state( &state, &caps ); + + 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 ); + + return 0; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +LRESULT CALLBACK test_di_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) + { + PAINTSTRUCT paint; + DIJOYSTATE state; + DIDEVCAPS caps; + RECT rect; + HDC hdc; + + get_device_state( &state, &caps ); + + 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 ); + + return 0; + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + LRESULT CALLBACK test_di_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 ); diff --git a/dlls/joy.cpl/joy.rc b/dlls/joy.cpl/joy.rc index 85900cf9576..d74afc38f58 100644 --- a/dlls/joy.cpl/joy.rc +++ b/dlls/joy.cpl/joy.rc @@ -55,10 +55,8 @@ CAPTION "DInput" FONT 8, "Ms Shell Dlg" { COMBOBOX IDC_DI_DEVICES, 15, 10, 291, 60, CBS_DROPDOWNLIST | CBS_HASSTRINGS - GROUPBOX "", IDC_DI_AXIS_X_Y, 15, 30, 60, 60 - GROUPBOX "", IDC_DI_AXIS_RX_RY, 92, 30, 60, 60 - GROUPBOX "", IDC_DI_AXIS_Z_RZ, 169, 30, 60, 60 - GROUPBOX "", IDC_DI_AXIS_POV_0, 246, 30, 60, 60 + GROUPBOX "Axes", IDC_DI_AXES, 15, 30, 214, 60 + GROUPBOX "POVs", IDC_DI_POVS, 246, 30, 60, 60 GROUPBOX "Buttons", IDC_DI_BUTTONS, 15, 100, 291, 70 LTEXT "Force Feedback Effect", IDC_STATIC, 15, 180, 291, 10 LISTBOX IDC_DI_EFFECTS, 15, 190, 291, 70, WS_TABSTOP | WS_VSCROLL | LBS_NOTIFY diff --git a/dlls/joy.cpl/joy_private.h b/dlls/joy.cpl/joy_private.h index 9c8a46c1c05..0dc9a02be9f 100644 --- a/dlls/joy.cpl/joy_private.h +++ b/dlls/joy.cpl/joy_private.h @@ -31,6 +31,8 @@ #include "resource.h"
extern void set_di_device_state( HWND hwnd, DIJOYSTATE *state, DIDEVCAPS *caps ); +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 );
extern INT_PTR CALLBACK test_xi_dialog_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); diff --git a/dlls/joy.cpl/main.c b/dlls/joy.cpl/main.c index ac9544167b6..fb41a8a2860 100644 --- a/dlls/joy.cpl/main.c +++ b/dlls/joy.cpl/main.c @@ -39,17 +39,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(joycpl);
#define TEST_MAX_BUTTONS 32 -#define TEST_MAX_AXES 4 #define TEST_POLL_TIME 100
-#define TEST_AXIS_X 43 -#define TEST_AXIS_Y 60 -#define TEST_NEXT_AXIS_X 77 -#define TEST_AXIS_SIZE_X 3 -#define TEST_AXIS_SIZE_Y 3 -#define TEST_AXIS_MIN -25 -#define TEST_AXIS_MAX 25 - #define FF_PLAY_TIME 2*DI_SECONDS #define FF_PERIOD_TIME FF_PLAY_TIME/4
@@ -68,7 +59,6 @@ struct device struct Graphics { HWND hwnd; - HWND axes[TEST_MAX_AXES]; };
struct JoystickData @@ -245,25 +235,14 @@ static BOOL CALLBACK enum_devices( const DIDEVICEINSTANCEW *instance, void *cont { DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)}; struct JoystickData *data = context; - DIPROPRANGE proprange; struct device *entry;
if (!(entry = calloc( 1, sizeof(*entry) ))) return DIENUM_STOP;
IDirectInput8_CreateDevice( data->di, &instance->guidInstance, &entry->device, NULL ); IDirectInputDevice8_SetDataFormat( entry->device, &c_dfDIJoystick ); - IDirectInputDevice8_GetCapabilities( entry->device, &caps );
- /* Set axis range to ease the GUI visualization */ - proprange.diph.dwSize = sizeof(DIPROPRANGE); - proprange.diph.dwHeaderSize = sizeof(DIPROPHEADER); - proprange.diph.dwHow = DIPH_DEVICE; - proprange.diph.dwObj = 0; - proprange.lMin = TEST_AXIS_MIN; - proprange.lMax = TEST_AXIS_MAX; - - IDirectInputDevice_SetProperty( entry->device, DIPROP_RANGE, &proprange.diph ); list_add_tail( &devices, &entry->entry );
return DIENUM_CONTINUE; @@ -595,28 +574,14 @@ static void dump_joy_state(DIJOYSTATE* st)
static DWORD WINAPI input_thread(void *param) { - int axes_pos[TEST_MAX_AXES][2]; struct JoystickData *data = param;
- /* Setup POV as clock positions - * 0 - * 31500 4500 - * 27000 -1 9000 - * 22500 13500 - * 18000 - */ - int ma = TEST_AXIS_MAX; - int pov_val[9] = {0, 4500, 9000, 13500, - 18000, 22500, 27000, 31500, -1}; - int pov_pos[9][2] = { {0, -ma}, {ma/2, -ma/2}, {ma, 0}, {ma/2, ma/2}, - {0, ma}, {-ma/2, ma/2}, {-ma, 0}, {-ma/2, -ma/2}, {0, 0} }; - while (!data->stop) { IDirectInputDevice8W *device; IDirectInputEffect *effect; DIJOYSTATE state = {0}; - unsigned int i, j; + unsigned int i;
if (WaitForSingleObject( device_state_event, TEST_POLL_TIME ) == WAIT_TIMEOUT) continue;
@@ -630,36 +595,6 @@ static DWORD WINAPI input_thread(void *param)
dump_joy_state(&state); set_di_device_state( data->di_dialog_hwnd, &state, &caps ); - - /* Indicate axis positions, axes showing are hardcoded for now */ - axes_pos[0][0] = state.lX; - axes_pos[0][1] = state.lY; - axes_pos[1][0] = state.lRx; - axes_pos[1][1] = state.lRy; - axes_pos[2][0] = state.lZ; - axes_pos[2][1] = state.lRz; - - /* Set pov values */ - for (j = 0; j < ARRAY_SIZE(pov_val); j++) - { - if (state.rgdwPOV[0] == pov_val[j]) - { - axes_pos[3][0] = pov_pos[j][0]; - axes_pos[3][1] = pov_pos[j][1]; - } - } - - for (i = 0; i < TEST_MAX_AXES; i++) - { - RECT r; - - r.left = (TEST_AXIS_X + TEST_NEXT_AXIS_X*i + axes_pos[i][0]); - r.top = (TEST_AXIS_Y + axes_pos[i][1]); - r.bottom = r.right = 0; /* unused */ - MapDialogRect(data->graphics.hwnd, &r); - - SetWindowPos(data->graphics.axes[i], 0, r.left, r.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE); - } }
if ((effect = get_selected_effect())) @@ -770,31 +705,6 @@ static void ff_handle_effectchange( HWND hwnd ) } }
-static void draw_joystick_axes(HWND hwnd, struct JoystickData* data) -{ - static const WCHAR *axes_names[TEST_MAX_AXES] = {L"X,Y", L"Rx,Ry", L"Z,Rz", L"POV"}; - static const DWORD axes_idc[TEST_MAX_AXES] = {IDC_DI_AXIS_X_Y, IDC_DI_AXIS_RX_RY, IDC_DI_AXIS_Z_RZ, IDC_DI_AXIS_POV_0}; - int i; - HINSTANCE hinst = (HINSTANCE) GetWindowLongPtrW(hwnd, GWLP_HINSTANCE); - - for (i = 0; i < TEST_MAX_AXES; i++) - { - RECT r; - /* Set axis box name */ - SetWindowTextW(GetDlgItem(hwnd, axes_idc[i]), axes_names[i]); - - r.left = (TEST_AXIS_X + TEST_NEXT_AXIS_X*i); - r.top = TEST_AXIS_Y; - r.right = r.left + TEST_AXIS_SIZE_X; - r.bottom = r.top + TEST_AXIS_SIZE_Y; - MapDialogRect(hwnd, &r); - - data->graphics.axes[i] = CreateWindowW(L"Button", NULL, WS_CHILD | WS_VISIBLE, - r.left, r.top, r.right - r.left, r.bottom - r.top, - hwnd, NULL, NULL, hinst); - } -} - /********************************************************************* * test_dlgproc [internal] * @@ -817,6 +727,14 @@ 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 ); @@ -829,6 +747,26 @@ static void create_device_views( HWND hwnd ) 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; @@ -853,7 +791,6 @@ static INT_PTR CALLBACK test_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM data = (struct JoystickData*) ((PROPSHEETPAGEW*)lparam)->lParam;
di_update_select_combo( hwnd ); - draw_joystick_axes(hwnd, data); create_device_views( hwnd );
return TRUE; @@ -1003,6 +940,18 @@ static void register_window_class(void) .lpfnWndProc = &test_xi_window_proc, .lpszClassName = L"JoyCplXInput", }; + WNDCLASSW di_axes_class = + { + .hInstance = hcpl, + .lpfnWndProc = &test_di_axes_window_proc, + .lpszClassName = L"JoyCplDInputAxes", + }; + WNDCLASSW di_povs_class = + { + .hInstance = hcpl, + .lpfnWndProc = &test_di_povs_window_proc, + .lpszClassName = L"JoyCplDInputPOVs", + }; WNDCLASSW di_buttons_class = { .hInstance = hcpl, @@ -1011,11 +960,15 @@ static void register_window_class(void) };
RegisterClassW( &xi_class ); + RegisterClassW( &di_axes_class ); + RegisterClassW( &di_povs_class ); RegisterClassW( &di_buttons_class ); }
static void unregister_window_class(void) { + UnregisterClassW( L"JoyCplDInputAxes", hcpl ); + UnregisterClassW( L"JoyCplDInputPOVs", hcpl ); UnregisterClassW( L"JoyCplDInputButtons", hcpl ); UnregisterClassW( L"JoyCplXInput", hcpl ); } diff --git a/dlls/joy.cpl/resource.h b/dlls/joy.cpl/resource.h index 35047d87642..a711617a607 100644 --- a/dlls/joy.cpl/resource.h +++ b/dlls/joy.cpl/resource.h @@ -47,12 +47,10 @@ #define IDC_BUTTONOVERRIDE 2013
#define IDC_DI_DEVICES 2100 -#define IDC_DI_AXIS_X_Y 2101 -#define IDC_DI_AXIS_RX_RY 2102 -#define IDC_DI_AXIS_Z_RZ 2103 -#define IDC_DI_AXIS_POV_0 2104 -#define IDC_DI_BUTTONS 2105 -#define IDC_DI_EFFECTS 2106 +#define IDC_DI_AXES 2101 +#define IDC_DI_POVS 2102 +#define IDC_DI_BUTTONS 2103 +#define IDC_DI_EFFECTS 2104
#define IDC_XI_USER_0 2200 #define IDC_XI_USER_1 2201