2 * Copyright 2022 RĂ©mi Bernon for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/debug.h"
32 #include "wine/list.h"
34 #include "joy_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(joycpl
);
41 IDirectInputEffect
*effect
;
47 IDirectInputDevice8W
*device
;
50 static CRITICAL_SECTION state_cs
;
51 static CRITICAL_SECTION_DEBUG state_cs_debug
=
54 { &state_cs_debug
.ProcessLocksList
, &state_cs_debug
.ProcessLocksList
},
55 0, 0, { (DWORD_PTR
)(__FILE__
": state_cs") }
57 static CRITICAL_SECTION state_cs
= { &state_cs_debug
, -1, 0, 0, 0, 0 };
59 static struct list effects
= LIST_INIT( effects
);
60 static IDirectInputEffect
*effect_selected
;
62 static struct list devices
= LIST_INIT( devices
);
63 static IDirectInputDevice8W
*device_selected
;
65 static HWND dialog_hwnd
;
66 static HANDLE state_event
;
68 static BOOL CALLBACK
enum_effects( const DIEFFECTINFOW
*info
, void *context
)
70 IDirectInputDevice8W
*device
= context
;
71 DWORD axes
[2] = {DIJOFS_X
, DIJOFS_Y
};
72 LONG direction
[2] = {0};
75 .dwSize
= sizeof(DIEFFECT
),
76 .dwFlags
= DIEFF_CARTESIAN
| DIEFF_OBJECTOFFSETS
,
77 .dwDuration
= 2 * DI_SECONDS
,
78 .dwGain
= DI_FFNOMINALMAX
,
79 .rglDirection
= direction
,
83 DICONSTANTFORCE constant
=
85 .lMagnitude
= DI_FFNOMINALMAX
,
89 .dwMagnitude
= DI_FFNOMINALMAX
,
90 .dwPeriod
= DI_SECONDS
/ 2,
92 DICONDITION condition
=
94 .dwPositiveSaturation
= 10000,
95 .dwNegativeSaturation
= 10000,
96 .lPositiveCoefficient
= 10000,
97 .lNegativeCoefficient
= 10000,
101 .lEnd
= DI_FFNOMINALMAX
,
103 IDirectInputEffect
*effect
;
104 struct effect
*entry
;
107 hr
= IDirectInputDevice8_Acquire( device
);
108 if (FAILED(hr
)) return DIENUM_CONTINUE
;
110 if (!(entry
= calloc( 1, sizeof(*entry
) ))) return DIENUM_STOP
;
112 if (IsEqualGUID( &info
->guid
, &GUID_RampForce
))
114 params
.cbTypeSpecificParams
= sizeof(ramp
);
115 params
.lpvTypeSpecificParams
= &ramp
;
116 params
.dwFlags
|= DIEP_TYPESPECIFICPARAMS
;
118 else if (IsEqualGUID( &info
->guid
, &GUID_ConstantForce
))
120 params
.cbTypeSpecificParams
= sizeof(constant
);
121 params
.lpvTypeSpecificParams
= &constant
;
122 params
.dwFlags
|= DIEP_TYPESPECIFICPARAMS
;
124 else if (IsEqualGUID( &info
->guid
, &GUID_Sine
) ||
125 IsEqualGUID( &info
->guid
, &GUID_Square
) ||
126 IsEqualGUID( &info
->guid
, &GUID_Triangle
) ||
127 IsEqualGUID( &info
->guid
, &GUID_SawtoothUp
) ||
128 IsEqualGUID( &info
->guid
, &GUID_SawtoothDown
))
130 params
.cbTypeSpecificParams
= sizeof(periodic
);
131 params
.lpvTypeSpecificParams
= &periodic
;
132 params
.dwFlags
|= DIEP_TYPESPECIFICPARAMS
;
134 else if (IsEqualGUID( &info
->guid
, &GUID_Spring
) ||
135 IsEqualGUID( &info
->guid
, &GUID_Damper
) ||
136 IsEqualGUID( &info
->guid
, &GUID_Inertia
) ||
137 IsEqualGUID( &info
->guid
, &GUID_Friction
))
139 params
.cbTypeSpecificParams
= sizeof(condition
);
140 params
.lpvTypeSpecificParams
= &condition
;
141 params
.dwFlags
|= DIEP_TYPESPECIFICPARAMS
;
144 do hr
= IDirectInputDevice2_CreateEffect( device
, &info
->guid
, ¶ms
, &effect
, NULL
);
145 while (FAILED(hr
) && --params
.cAxes
);
149 FIXME( "Failed to create effect with type %s, hr %#lx\n", debugstr_guid( &info
->guid
), hr
);
151 return DIENUM_CONTINUE
;
154 entry
->effect
= effect
;
155 list_add_tail( &effects
, &entry
->entry
);
157 return DIENUM_CONTINUE
;
160 static void set_selected_effect( IDirectInputEffect
*effect
)
162 IDirectInputEffect
*previous
;
164 EnterCriticalSection( &state_cs
);
165 if ((previous
= effect_selected
)) IDirectInputEffect_Release( previous
);
166 if ((effect_selected
= effect
)) IDirectInput_AddRef( effect
);
167 LeaveCriticalSection( &state_cs
);
170 static IDirectInputEffect
*get_selected_effect(void)
172 IDirectInputEffect
*effect
;
174 EnterCriticalSection( &state_cs
);
175 if ((effect
= effect_selected
)) IDirectInputEffect_AddRef( effect
);
176 LeaveCriticalSection( &state_cs
);
181 static void clear_effects(void)
183 struct effect
*effect
, *next
;
185 set_selected_effect( NULL
);
187 LIST_FOR_EACH_ENTRY_SAFE( effect
, next
, &effects
, struct effect
, entry
)
189 list_remove( &effect
->entry
);
190 IDirectInputEffect_Release( effect
->effect
);
195 static void set_selected_device( IDirectInputDevice8W
*device
)
197 IDirectInputDevice8W
*previous
;
199 EnterCriticalSection( &state_cs
);
201 set_selected_effect( NULL
);
203 if ((previous
= device_selected
))
205 IDirectInputDevice8_SetEventNotification( previous
, NULL
);
206 IDirectInputDevice8_Release( previous
);
208 if ((device_selected
= device
))
210 IDirectInputDevice8_AddRef( device
);
211 IDirectInputDevice8_SetEventNotification( device
, state_event
);
212 IDirectInputDevice8_Acquire( device
);
215 LeaveCriticalSection( &state_cs
);
218 static IDirectInputDevice8W
*get_selected_device(void)
220 IDirectInputDevice8W
*device
;
222 EnterCriticalSection( &state_cs
);
223 device
= device_selected
;
224 if (device
) IDirectInputDevice8_AddRef( device
);
225 LeaveCriticalSection( &state_cs
);
230 static BOOL CALLBACK
enum_devices( const DIDEVICEINSTANCEW
*instance
, void *context
)
232 DIDEVCAPS caps
= {.dwSize
= sizeof(DIDEVCAPS
)};
233 IDirectInput8W
*dinput
= context
;
234 struct device
*entry
;
236 if (!(entry
= calloc( 1, sizeof(*entry
) ))) return DIENUM_STOP
;
238 IDirectInput8_CreateDevice( dinput
, &instance
->guidInstance
, &entry
->device
, NULL
);
239 IDirectInputDevice8_SetDataFormat( entry
->device
, &c_dfDIJoystick2
);
240 IDirectInputDevice8_GetCapabilities( entry
->device
, &caps
);
242 list_add_tail( &devices
, &entry
->entry
);
244 return DIENUM_CONTINUE
;
247 static void clear_devices(void)
249 struct device
*entry
, *next
;
251 set_selected_device( NULL
);
253 LIST_FOR_EACH_ENTRY_SAFE( entry
, next
, &devices
, struct device
, entry
)
255 list_remove( &entry
->entry
);
256 IDirectInputDevice8_Unacquire( entry
->device
);
257 IDirectInputDevice8_Release( entry
->device
);
262 static DWORD WINAPI
input_thread( void *param
)
264 HANDLE events
[2] = {param
, state_event
};
266 while (WaitForMultipleObjects( 2, events
, FALSE
, INFINITE
) != 0)
268 IDirectInputEffect
*effect
;
269 DIJOYSTATE2 state
= {0};
272 SendMessageW( dialog_hwnd
, WM_USER
, 0, 0 );
274 if ((effect
= get_selected_effect()))
276 DWORD flags
= DIEP_AXES
| DIEP_DIRECTION
| DIEP_NORESTART
;
277 LONG direction
[3] = {0};
281 .dwSize
= sizeof(DIEFFECT
),
282 .dwFlags
= DIEFF_CARTESIAN
| DIEFF_OBJECTOFFSETS
,
283 .rglDirection
= direction
,
288 IDirectInputEffect_GetParameters( effect
, ¶ms
, flags
);
289 params
.rgdwAxes
[0] = state
.lX
;
290 params
.rgdwAxes
[1] = state
.lY
;
292 for (i
= 0; i
< ARRAY_SIZE(state
.rgbButtons
); i
++)
294 if (state
.rgbButtons
[i
])
296 IDirectInputEffect_SetParameters( effect
, ¶ms
, flags
);
297 IDirectInputEffect_Start( effect
, 1, 0 );
302 IDirectInputEffect_Release( effect
);
309 static void draw_axis_view( HDC hdc
, RECT rect
, const WCHAR
*name
, LONG value
)
313 .x
= (rect
.left
+ rect
.right
) / 2 + 10,
314 .y
= (rect
.top
+ rect
.bottom
) / 2,
316 LONG w
= (rect
.bottom
- rect
.top
+ 1) / 3;
317 LONG x
= rect
.left
+ 20 + (w
+ 1) / 2 + MulDiv( value
, rect
.right
- rect
.left
- 20 - w
, 0xffff );
321 FillRect( hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1) );
323 color
= SetTextColor( hdc
, GetSysColor( COLOR_WINDOWTEXT
) );
324 font
= SelectObject( hdc
, GetStockObject( ANSI_VAR_FONT
) );
325 DrawTextW( hdc
, name
, -1, &rect
, DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
| DT_NOCLIP
);
326 SetTextColor( hdc
, color
);
327 SelectObject( hdc
, font
);
329 SetDCBrushColor( hdc
, GetSysColor( COLOR_WINDOW
) );
330 SetDCPenColor( hdc
, GetSysColor( COLOR_WINDOWFRAME
) );
331 SelectObject( hdc
, GetStockObject( DC_BRUSH
) );
332 SelectObject( hdc
, GetStockObject( DC_PEN
) );
334 RoundRect( hdc
, rect
.left
+ 20, rect
.top
, rect
.right
, rect
.bottom
, 5, 5 );
338 MoveToEx( hdc
, center
.x
, center
.y
- 3, NULL
);
339 LineTo( hdc
, center
.x
, center
.y
+ 3 );
342 SetDCBrushColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
343 SetDCPenColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
345 Rectangle( hdc
, rect
.left
+ 20, rect
.top
+ w
, x
, rect
.bottom
- w
);
349 MoveToEx( hdc
, center
.x
, center
.y
- 3, NULL
);
350 LineTo( hdc
, center
.x
, center
.y
+ 3 );
354 static void draw_pov_view( HDC hdc
, RECT rect
, DWORD value
)
359 {.x
= round( rect
.left
* 0.71 + rect
.right
* 0.29 ), .y
= round( rect
.top
* 1.00 + rect
.bottom
* 0.00 )},
360 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
362 {.x
= round( rect
.left
* 0.29 + rect
.right
* 0.71 ), .y
= round( rect
.top
* 1.00 + rect
.bottom
* 0.00 )},
363 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
365 {.x
= round( rect
.left
* 0.00 + rect
.right
* 1.00 ), .y
= round( rect
.top
* 0.71 + rect
.bottom
* 0.29 )},
366 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
368 {.x
= round( rect
.left
* 0.00 + rect
.right
* 1.00 ), .y
= round( rect
.top
* 0.29 + rect
.bottom
* 0.71 )},
369 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
371 {.x
= round( rect
.left
* 0.29 + rect
.right
* 0.71 ), .y
= round( rect
.top
* 0.00 + rect
.bottom
* 1.00 )},
372 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
374 {.x
= round( rect
.left
* 0.71 + rect
.right
* 0.29 ), .y
= round( rect
.top
* 0.00 + rect
.bottom
* 1.00 )},
375 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
377 {.x
= round( rect
.left
* 1.00 + rect
.right
* 0.00 ), .y
= round( rect
.top
* 0.29 + rect
.bottom
* 0.71 )},
378 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
380 {.x
= round( rect
.left
* 1.00 + rect
.right
* 0.00 ), .y
= round( rect
.top
* 0.71 + rect
.bottom
* 0.29 )},
381 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
383 {.x
= round( rect
.left
* 0.71 + rect
.right
* 0.29 ), .y
= round( rect
.top
* 1.00 + rect
.bottom
* 0.00 )},
384 {.x
= round( rect
.left
* 0.50 + rect
.right
* 0.50 ), .y
= round( rect
.top
* 0.50 + rect
.bottom
* 0.50 )},
385 {.x
= round( rect
.left
* 0.71 + rect
.right
* 0.29 ), .y
= round( rect
.top
* 1.00 + rect
.bottom
* 0.00 )},
389 FillRect( hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1) );
391 SetDCBrushColor( hdc
, GetSysColor( COLOR_WINDOW
) );
392 SetDCPenColor( hdc
, GetSysColor( COLOR_WINDOWFRAME
) );
393 SelectObject( hdc
, GetStockObject( DC_BRUSH
) );
394 SelectObject( hdc
, GetStockObject( DC_PEN
) );
396 for (i
= 0; i
< ARRAY_SIZE(points
) - 1; i
+= 2)
398 MoveToEx( hdc
, (points
[i
].x
+ points
[i
+ 1].x
) / 2, (points
[i
].y
+ points
[i
+ 1].y
) / 2, NULL
);
399 LineTo( hdc
, points
[i
].x
, points
[i
].y
);
402 SetDCPenColor( hdc
, GetSysColor( (value
!= -1) ? COLOR_HIGHLIGHTTEXT
: COLOR_WINDOWFRAME
) );
403 SetDCBrushColor( hdc
, GetSysColor( (value
!= -1) ? COLOR_HIGHLIGHT
: COLOR_WINDOW
) );
404 if (value
!= -1) Polygon( hdc
, points
+ value
/ 4500 * 2, 3 );
407 static void draw_button_view( HDC hdc
, RECT rect
, BOOL set
, const WCHAR
*name
)
413 FillRect( hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1) );
415 SetDCBrushColor( hdc
, GetSysColor( set
? COLOR_HIGHLIGHT
: COLOR_WINDOW
) );
416 SetDCPenColor( hdc
, GetSysColor( set
? COLOR_HIGHLIGHTTEXT
: COLOR_WINDOWFRAME
) );
417 SelectObject( hdc
, GetStockObject( DC_BRUSH
) );
418 SelectObject( hdc
, GetStockObject( DC_PEN
) );
420 if (rect
.right
- rect
.left
< 16) Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
421 else Ellipse( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
423 color
= SetTextColor( hdc
, GetSysColor( set
? COLOR_HIGHLIGHTTEXT
: COLOR_WINDOWTEXT
) );
424 font
= SelectObject( hdc
, GetStockObject( ANSI_VAR_FONT
) );
425 mode
= SetBkMode( hdc
, TRANSPARENT
);
426 DrawTextW( hdc
, name
, -1, &rect
, DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
| DT_NOCLIP
);
427 SetBkMode( hdc
, mode
);
428 SetTextColor( hdc
, color
);
429 SelectObject( hdc
, font
);
432 LRESULT CALLBACK
test_di_axes_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
434 TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
438 DIDEVCAPS caps
= {.dwSize
= sizeof(DIDEVCAPS
)};
439 IDirectInputDevice8W
*device
;
440 DIJOYSTATE2 state
= {0};
445 if ((device
= get_selected_device()))
447 IDirectInputDevice8_GetDeviceState( device
, sizeof(state
), &state
);
448 IDirectInputDevice8_GetCapabilities( device
, &caps
);
449 IDirectInputDevice8_Release( device
);
452 hdc
= BeginPaint( hwnd
, &paint
);
454 GetClientRect( hwnd
, &rect
);
455 rect
.bottom
= rect
.top
+ (rect
.bottom
- rect
.top
- 2) / 4 - 2;
456 rect
.right
= rect
.left
+ (rect
.right
- rect
.left
) / 2 - 10;
458 OffsetRect( &rect
, 5, 2 );
459 draw_axis_view( hdc
, rect
, L
"X", state
.lX
);
462 OffsetRect( &rect
, rect
.right
- rect
.left
+ 10, 0 );
463 draw_axis_view( hdc
, rect
, L
"Rx", state
.lRx
);
466 OffsetRect( &rect
, 0, rect
.bottom
- rect
.top
+ 2 );
467 draw_axis_view( hdc
, rect
, L
"Y", state
.lY
);
470 OffsetRect( &rect
, rect
.right
- rect
.left
+ 10, 0 );
471 draw_axis_view( hdc
, rect
, L
"Ry", state
.lRy
);
474 OffsetRect( &rect
, 0, rect
.bottom
- rect
.top
+ 2 );
475 draw_axis_view( hdc
, rect
, L
"Z", state
.lZ
);
478 OffsetRect( &rect
, rect
.right
- rect
.left
+ 10, 0 );
479 draw_axis_view( hdc
, rect
, L
"Rz", state
.lRz
);
482 OffsetRect( &rect
, 0, rect
.bottom
- rect
.top
+ 2 );
483 draw_axis_view( hdc
, rect
, L
"S", state
.rglSlider
[0] );
486 OffsetRect( &rect
, rect
.right
- rect
.left
+ 10, 0 );
487 draw_axis_view( hdc
, rect
, L
"Rs", state
.rglSlider
[1] );
490 EndPaint( hwnd
, &paint
);
495 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
498 LRESULT CALLBACK
test_di_povs_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
500 TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
504 DIDEVCAPS caps
= {.dwSize
= sizeof(DIDEVCAPS
)};
505 IDirectInputDevice8W
*device
;
506 DIJOYSTATE2 state
= {0};
511 if ((device
= get_selected_device()))
513 IDirectInputDevice8_GetDeviceState( device
, sizeof(state
), &state
);
514 IDirectInputDevice8_GetCapabilities( device
, &caps
);
515 IDirectInputDevice8_Release( device
);
518 hdc
= BeginPaint( hwnd
, &paint
);
520 GetClientRect( hwnd
, &rect
);
521 rect
.bottom
= rect
.top
+ (rect
.bottom
- rect
.top
- 5) / 2 - 5;
522 rect
.right
= rect
.left
+ (rect
.bottom
- rect
.top
);
524 OffsetRect( &rect
, 5, 5 );
525 draw_pov_view( hdc
, rect
, state
.rgdwPOV
[0] );
526 OffsetRect( &rect
, rect
.right
- rect
.left
+ 5, 0 );
527 draw_pov_view( hdc
, rect
, state
.rgdwPOV
[1] );
528 OffsetRect( &rect
, rect
.left
- rect
.right
- 5, rect
.bottom
- rect
.top
+ 5 );
529 draw_pov_view( hdc
, rect
, state
.rgdwPOV
[1] );
530 OffsetRect( &rect
, rect
.right
- rect
.left
+ 5, 0 );
531 draw_pov_view( hdc
, rect
, state
.rgdwPOV
[2] );
533 EndPaint( hwnd
, &paint
);
538 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
541 LRESULT CALLBACK
test_di_buttons_window_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
543 TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
547 DIDEVCAPS caps
= {.dwSize
= sizeof(DIDEVCAPS
)};
548 UINT i
, j
, offs
, size
, step
, space
= 2;
549 IDirectInputDevice8W
*device
;
550 DIJOYSTATE2 state
= {0};
555 if ((device
= get_selected_device()))
557 IDirectInputDevice8_GetDeviceState( device
, sizeof(state
), &state
);
558 IDirectInputDevice8_GetCapabilities( device
, &caps
);
559 IDirectInputDevice8_Release( device
);
562 if (caps
.dwButtons
<= 48) step
= 16;
565 hdc
= BeginPaint( hwnd
, &paint
);
567 GetClientRect( hwnd
, &rect
);
568 FillRect( hdc
, &rect
, (HBRUSH
)(COLOR_WINDOW
+ 1) );
570 size
= (rect
.right
- rect
.left
- space
) / step
;
571 offs
= (rect
.right
- rect
.left
- step
* size
- space
) / 2;
572 OffsetRect( &rect
, offs
, offs
);
573 rect
.right
= rect
.left
+ size
- space
;
574 rect
.bottom
= rect
.top
+ size
- space
;
576 for (i
= 0; i
< ARRAY_SIZE(state
.rgbButtons
) && i
< caps
.dwButtons
;)
580 for (j
= 0; j
< step
&& i
< caps
.dwButtons
; j
++, i
++)
583 if (step
== 24) swprintf( buffer
, ARRAY_SIZE(buffer
), L
"%02x", i
);
584 else swprintf( buffer
, ARRAY_SIZE(buffer
), L
"%d", i
);
585 draw_button_view( hdc
, rect
, state
.rgbButtons
[i
], buffer
);
586 OffsetRect( &rect
, size
, 0 );
590 OffsetRect( &rect
, 0, size
);
593 EndPaint( hwnd
, &paint
);
598 return DefWindowProcW( hwnd
, msg
, wparam
, lparam
);
601 static void update_di_effects( HWND hwnd
, IDirectInputDevice8W
*device
)
603 struct effect
*effect
;
607 IDirectInputDevice8_EnumEffects( device
, enum_effects
, device
, 0 );
609 SendDlgItemMessageW( hwnd
, IDC_DI_EFFECTS
, LB_RESETCONTENT
, 0, 0 );
610 SendDlgItemMessageW( hwnd
, IDC_DI_EFFECTS
, LB_ADDSTRING
, 0, (LPARAM
)L
"None" );
612 LIST_FOR_EACH_ENTRY( effect
, &effects
, struct effect
, entry
)
614 DIEFFECTINFOW info
= {.dwSize
= sizeof(DIEFFECTINFOW
)};
617 if (FAILED(IDirectInputEffect_GetEffectGuid( effect
->effect
, &guid
))) continue;
618 if (FAILED(IDirectInputDevice8_GetEffectInfo( device
, &info
, &guid
))) continue;
619 SendDlgItemMessageW( hwnd
, IDC_DI_EFFECTS
, LB_ADDSTRING
, 0, (LPARAM
)( info
.tszName
+ 5 ) );
623 static void handle_di_effects_change( HWND hwnd
)
625 IDirectInputDevice8W
*device
;
629 set_selected_effect( NULL
);
631 sel
= SendDlgItemMessageW( hwnd
, IDC_DI_EFFECTS
, LB_GETCURSEL
, 0, 0 ) - 1;
634 entry
= list_head( &effects
);
635 while (sel
-- && entry
) entry
= list_next( &effects
, entry
);
638 set_selected_effect( LIST_ENTRY( entry
, struct effect
, entry
)->effect
);
640 if ((device
= get_selected_device()))
642 IDirectInputDevice8_Unacquire( device
);
643 IDirectInputDevice8_SetCooperativeLevel( device
, GetAncestor( hwnd
, GA_ROOT
), DISCL_BACKGROUND
| DISCL_EXCLUSIVE
);
644 IDirectInputDevice8_Acquire( device
);
645 IDirectInputDevice8_Release( device
);
649 static void create_device_views( HWND hwnd
)
651 HINSTANCE instance
= (HINSTANCE
)GetWindowLongPtrW( hwnd
, GWLP_HINSTANCE
);
656 parent
= GetDlgItem( hwnd
, IDC_DI_AXES
);
657 GetClientRect( parent
, &rect
);
660 margin
= (rect
.bottom
- rect
.top
) * 10 / 100;
661 InflateRect( &rect
, -margin
, -margin
);
663 CreateWindowW( L
"JoyCplDInputAxes", NULL
, WS_CHILD
| WS_VISIBLE
, rect
.left
, rect
.top
,
664 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, parent
, NULL
, NULL
, instance
);
666 parent
= GetDlgItem( hwnd
, IDC_DI_POVS
);
667 GetClientRect( parent
, &rect
);
670 margin
= (rect
.bottom
- rect
.top
) * 10 / 100;
671 InflateRect( &rect
, -margin
, -margin
);
673 CreateWindowW( L
"JoyCplDInputPOVs", NULL
, WS_CHILD
| WS_VISIBLE
, rect
.left
, rect
.top
,
674 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, parent
, NULL
, NULL
, instance
);
676 parent
= GetDlgItem( hwnd
, IDC_DI_BUTTONS
);
677 GetClientRect( parent
, &rect
);
680 margin
= (rect
.bottom
- rect
.top
) * 5 / 100;
681 InflateRect( &rect
, -margin
, -margin
);
683 CreateWindowW( L
"JoyCplDInputButtons", NULL
, WS_CHILD
| WS_VISIBLE
, rect
.left
, rect
.top
,
684 rect
.right
- rect
.left
, rect
.bottom
- rect
.top
, parent
, NULL
, NULL
, instance
);
687 static void handle_di_devices_change( HWND hwnd
)
689 DIDEVCAPS caps
= {.dwSize
= sizeof(DIDEVCAPS
)};
690 IDirectInputDevice8W
*device
;
694 set_selected_device( NULL
);
696 i
= SendDlgItemMessageW( hwnd
, IDC_DI_DEVICES
, CB_GETCURSEL
, 0, 0 );
699 entry
= list_head( &devices
);
700 while (i
-- && entry
) entry
= list_next( &devices
, entry
);
703 device
= LIST_ENTRY( entry
, struct device
, entry
)->device
;
704 if (FAILED(IDirectInputDevice8_GetCapabilities( device
, &caps
))) return;
706 set_selected_device( device
);
707 update_di_effects( hwnd
, device
);
710 static void update_di_devices( HWND hwnd
)
712 IDirectInput8W
*dinput
;
713 struct device
*entry
;
717 DirectInput8Create( GetModuleHandleW( NULL
), DIRECTINPUT_VERSION
, &IID_IDirectInput8W
, (void **)&dinput
, NULL
);
718 IDirectInput8_EnumDevices( dinput
, DI8DEVCLASS_GAMECTRL
, enum_devices
, dinput
, DIEDFL_ATTACHEDONLY
);
719 IDirectInput8_Release( dinput
);
721 SendDlgItemMessageW( hwnd
, IDC_DI_DEVICES
, CB_RESETCONTENT
, 0, 0 );
723 LIST_FOR_EACH_ENTRY( entry
, &devices
, struct device
, entry
)
725 DIDEVICEINSTANCEW info
= {.dwSize
= sizeof(DIDEVICEINSTANCEW
)};
726 if (FAILED(IDirectInputDevice8_GetDeviceInfo( entry
->device
, &info
))) continue;
727 SendDlgItemMessageW( hwnd
, IDC_DI_DEVICES
, CB_ADDSTRING
, 0, (LPARAM
)info
.tszInstanceName
);
731 static void update_device_views( HWND hwnd
)
735 parent
= GetDlgItem( hwnd
, IDC_DI_AXES
);
736 view
= FindWindowExW( parent
, NULL
, L
"JoyCplDInputAxes", NULL
);
737 InvalidateRect( view
, NULL
, TRUE
);
739 parent
= GetDlgItem( hwnd
, IDC_DI_POVS
);
740 view
= FindWindowExW( parent
, NULL
, L
"JoyCplDInputPOVs", NULL
);
741 InvalidateRect( view
, NULL
, TRUE
);
743 parent
= GetDlgItem( hwnd
, IDC_DI_BUTTONS
);
744 view
= FindWindowExW( parent
, NULL
, L
"JoyCplDInputButtons", NULL
);
745 InvalidateRect( view
, NULL
, TRUE
);
748 INT_PTR CALLBACK
test_di_dialog_proc( HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
750 static HANDLE thread
, thread_stop
;
752 TRACE( "hwnd %p, msg %#x, wparam %#Ix, lparam %#Ix\n", hwnd
, msg
, wparam
, lparam
);
757 create_device_views( hwnd
);
763 case MAKEWPARAM( IDC_DI_DEVICES
, CBN_SELCHANGE
):
764 handle_di_devices_change( hwnd
);
766 SendDlgItemMessageW( hwnd
, IDC_DI_EFFECTS
, LB_SETCURSEL
, 0, 0 );
767 handle_di_effects_change( hwnd
);
769 update_device_views( hwnd
);
772 case MAKEWPARAM( IDC_DI_EFFECTS
, LBN_SELCHANGE
):
773 handle_di_effects_change( hwnd
);
779 switch (((NMHDR
*)lparam
)->code
)
783 state_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
784 thread_stop
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
786 update_di_devices( hwnd
);
788 SendDlgItemMessageW( hwnd
, IDC_DI_DEVICES
, CB_SETCURSEL
, 0, 0 );
789 handle_di_devices_change( hwnd
);
791 SendDlgItemMessageW( hwnd
, IDC_DI_EFFECTS
, LB_SETCURSEL
, 0, 0 );
792 handle_di_effects_change( hwnd
);
794 thread
= CreateThread( NULL
, 0, input_thread
, (void *)thread_stop
, 0, NULL
);
799 SetEvent( thread_stop
);
800 /* wait for the input thread to stop, processing any WM_USER message from it */
801 while (MsgWaitForMultipleObjects( 1, &thread
, FALSE
, INFINITE
, QS_ALLINPUT
) == 1)
804 while (PeekMessageW( &msg
, 0, 0, 0, PM_REMOVE
))
806 TranslateMessage( &msg
);
807 DispatchMessageW( &msg
);
810 CloseHandle( state_event
);
811 CloseHandle( thread_stop
);
812 CloseHandle( thread
);
821 update_device_views( hwnd
);