2 * Joystick testing control panel applet
4 * Copyright 2012 Lucas Fialho Zawacki
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wine/debug.h"
35 #include "wine/list.h"
37 #include "joy_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(joycpl
);
44 IDirectInputDevice8W
*device
;
49 static CRITICAL_SECTION joy_cs
;
50 static CRITICAL_SECTION_DEBUG joy_cs_debug
=
53 { &joy_cs_debug
.ProcessLocksList
, &joy_cs_debug
.ProcessLocksList
},
54 0, 0, { (DWORD_PTR
)(__FILE__
": joy_cs") }
56 static CRITICAL_SECTION joy_cs
= { &joy_cs_debug
, -1, 0, 0, 0, 0 };
58 static struct list devices
= LIST_INIT( devices
);
60 /*********************************************************************
63 BOOL WINAPI
DllMain(HINSTANCE hdll
, DWORD reason
, LPVOID reserved
)
65 TRACE("(%p, %ld, %p)\n", hdll
, reason
, reserved
);
69 case DLL_PROCESS_ATTACH
:
70 DisableThreadLibraryCalls(hdll
);
76 static BOOL CALLBACK
enum_devices( const DIDEVICEINSTANCEW
*instance
, void *context
)
78 DIDEVCAPS caps
= {.dwSize
= sizeof(DIDEVCAPS
)};
79 IDirectInput8W
*dinput
= context
;
82 if (!(entry
= calloc( 1, sizeof(*entry
) ))) return DIENUM_STOP
;
84 IDirectInput8_CreateDevice( dinput
, &instance
->guidInstance
, &entry
->device
, NULL
);
85 IDirectInputDevice8_SetDataFormat( entry
->device
, &c_dfDIJoystick
);
86 IDirectInputDevice8_GetCapabilities( entry
->device
, &caps
);
88 list_add_tail( &devices
, &entry
->entry
);
90 return DIENUM_CONTINUE
;
93 static void clear_devices(void)
95 struct device
*entry
, *next
;
97 LIST_FOR_EACH_ENTRY_SAFE( entry
, next
, &devices
, struct device
, entry
)
99 list_remove( &entry
->entry
);
100 IDirectInputDevice8_Unacquire( entry
->device
);
101 IDirectInputDevice8_Release( entry
->device
);
106 /******************************************************************************
107 * get_app_key [internal]
108 * Get the default DirectInput key and the selected app config key.
110 static BOOL
get_app_key(HKEY
*defkey
, HKEY
*appkey
)
114 /* Registry key can be found in HKCU\Software\Wine\DirectInput */
115 if (RegCreateKeyExW(HKEY_CURRENT_USER
, L
"Software\\Wine\\DirectInput\\Joysticks", 0, NULL
, 0,
116 KEY_SET_VALUE
| KEY_READ
, NULL
, defkey
, NULL
))
119 return *defkey
|| *appkey
;
122 /******************************************************************************
123 * set_config_key [internal]
124 * Writes a string value to a registry key, deletes the key if value == NULL
126 static DWORD
set_config_key(HKEY defkey
, HKEY appkey
, const WCHAR
*name
, const WCHAR
*value
, DWORD size
)
130 if (appkey
&& !RegDeleteValueW(appkey
, name
))
133 if (defkey
&& !RegDeleteValueW(defkey
, name
))
138 if (appkey
&& !RegSetValueExW(appkey
, name
, 0, REG_SZ
, (const BYTE
*) value
, (size
+ 1)*sizeof(WCHAR
)))
141 if (defkey
&& !RegSetValueExW(defkey
, name
, 0, REG_SZ
, (const BYTE
*) value
, (size
+ 1)*sizeof(WCHAR
)))
145 return ERROR_FILE_NOT_FOUND
;
148 /******************************************************************************
149 * enable_joystick [internal]
150 * Writes to the DirectInput registry key that enables/disables a joystick
151 * from being enumerated.
153 static void enable_joystick(WCHAR
*joy_name
, BOOL enable
)
157 get_app_key(&hkey
, &appkey
);
160 set_config_key(hkey
, appkey
, joy_name
, L
"disabled", wcslen(L
"disabled"));
162 set_config_key(hkey
, appkey
, joy_name
, NULL
, 0);
164 if (hkey
) RegCloseKey(hkey
);
165 if (appkey
) RegCloseKey(appkey
);
168 static void refresh_joystick_list( HWND hwnd
)
170 IDirectInput8W
*dinput
;
171 struct device
*entry
;
179 DirectInput8Create( GetModuleHandleW( NULL
), DIRECTINPUT_VERSION
, &IID_IDirectInput8W
, (void **)&dinput
, NULL
);
180 IDirectInput8_EnumDevices( dinput
, DI8DEVCLASS_GAMECTRL
, enum_devices
, dinput
, DIEDFL_ATTACHEDONLY
);
181 IDirectInput8_Release( dinput
);
183 SendDlgItemMessageW(hwnd
, IDC_JOYSTICKLIST
, LB_RESETCONTENT
, 0, 0);
184 SendDlgItemMessageW(hwnd
, IDC_DISABLEDLIST
, LB_RESETCONTENT
, 0, 0);
185 SendDlgItemMessageW(hwnd
, IDC_XINPUTLIST
, LB_RESETCONTENT
, 0, 0);
187 LIST_FOR_EACH_ENTRY( entry
, &devices
, struct device
, entry
)
189 DIDEVICEINSTANCEW info
= {.dwSize
= sizeof(DIDEVICEINSTANCEW
)};
190 DIPROPGUIDANDPATH prop
=
194 .dwSize
= sizeof(DIPROPGUIDANDPATH
),
195 .dwHeaderSize
= sizeof(DIPROPHEADER
),
196 .dwHow
= DIPH_DEVICE
,
200 if (FAILED(IDirectInputDevice8_GetDeviceInfo( entry
->device
, &info
))) continue;
201 if (FAILED(IDirectInputDevice8_GetProperty( entry
->device
, DIPROP_GUIDANDPATH
, &prop
.diph
))) continue;
203 if (wcsstr( prop
.wszPath
, L
"&ig_" )) SendDlgItemMessageW( hwnd
, IDC_XINPUTLIST
, LB_ADDSTRING
, 0, (LPARAM
)info
.tszInstanceName
);
204 else SendDlgItemMessageW( hwnd
, IDC_JOYSTICKLIST
, LB_ADDSTRING
, 0, (LPARAM
)info
.tszInstanceName
);
207 /* Search for disabled joysticks */
208 get_app_key(&hkey
, &appkey
);
209 RegQueryInfoKeyW(hkey
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &values
, NULL
, NULL
, NULL
, NULL
);
211 for (i
=0; i
< values
; i
++)
213 DWORD name_len
= MAX_PATH
, data_len
= MAX_PATH
;
214 WCHAR buf_name
[MAX_PATH
+ 9], buf_data
[MAX_PATH
];
216 status
= RegEnumValueW(hkey
, i
, buf_name
, &name_len
, NULL
, NULL
, (BYTE
*) buf_data
, &data_len
);
218 if (status
== ERROR_SUCCESS
&& !wcscmp(L
"disabled", buf_data
))
219 SendDlgItemMessageW(hwnd
, IDC_DISABLEDLIST
, LB_ADDSTRING
, 0, (LPARAM
) buf_name
);
222 if (hkey
) RegCloseKey(hkey
);
223 if (appkey
) RegCloseKey(appkey
);
226 static void override_joystick(WCHAR
*joy_name
, BOOL override
)
230 get_app_key(&hkey
, &appkey
);
233 set_config_key(hkey
, appkey
, joy_name
, L
"override", wcslen(L
"override"));
235 set_config_key(hkey
, appkey
, joy_name
, NULL
, 0);
237 if (hkey
) RegCloseKey(hkey
);
238 if (appkey
) RegCloseKey(appkey
);
241 /*********************************************************************
242 * list_dlgproc [internal]
245 static INT_PTR CALLBACK
list_dlgproc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
247 WCHAR instance_name
[MAX_PATH
] = {0};
250 TRACE("(%p, 0x%08x/%d, 0x%Ix)\n", hwnd
, msg
, msg
, lparam
);
255 refresh_joystick_list( hwnd
);
257 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONENABLE
), FALSE
);
258 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONDISABLE
), FALSE
);
259 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONRESET
), FALSE
);
260 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONOVERRIDE
), FALSE
);
267 switch (LOWORD(wparam
))
269 case IDC_BUTTONDISABLE
:
271 if ((sel
= SendDlgItemMessageW(hwnd
, IDC_JOYSTICKLIST
, LB_GETCURSEL
, 0, 0)) >= 0)
272 SendDlgItemMessageW(hwnd
, IDC_JOYSTICKLIST
, LB_GETTEXT
, sel
, (LPARAM
)instance_name
);
273 if ((sel
= SendDlgItemMessageW(hwnd
, IDC_XINPUTLIST
, LB_GETCURSEL
, 0, 0)) >= 0)
274 SendDlgItemMessageW(hwnd
, IDC_XINPUTLIST
, LB_GETTEXT
, sel
, (LPARAM
)instance_name
);
276 if (instance_name
[0])
278 enable_joystick(instance_name
, FALSE
);
279 refresh_joystick_list( hwnd
);
284 case IDC_BUTTONENABLE
:
286 if ((sel
= SendDlgItemMessageW(hwnd
, IDC_DISABLEDLIST
, LB_GETCURSEL
, 0, 0)) >= 0)
287 SendDlgItemMessageW(hwnd
, IDC_DISABLEDLIST
, LB_GETTEXT
, sel
, (LPARAM
)instance_name
);
289 if (instance_name
[0])
291 enable_joystick(instance_name
, TRUE
);
292 refresh_joystick_list( hwnd
);
297 case IDC_BUTTONRESET
:
299 if ((sel
= SendDlgItemMessageW(hwnd
, IDC_JOYSTICKLIST
, LB_GETCURSEL
, 0, 0)) >= 0)
301 SendDlgItemMessageW(hwnd
, IDC_JOYSTICKLIST
, LB_GETTEXT
, sel
, (LPARAM
)instance_name
);
302 override_joystick(instance_name
, FALSE
);
303 refresh_joystick_list( hwnd
);
308 case IDC_BUTTONOVERRIDE
:
310 if ((sel
= SendDlgItemMessageW(hwnd
, IDC_XINPUTLIST
, LB_GETCURSEL
, 0, 0)) >= 0)
312 SendDlgItemMessageW(hwnd
, IDC_XINPUTLIST
, LB_GETTEXT
, sel
, (LPARAM
)instance_name
);
313 override_joystick(instance_name
, TRUE
);
314 refresh_joystick_list( hwnd
);
319 case IDC_JOYSTICKLIST
:
320 SendDlgItemMessageW(hwnd
, IDC_DISABLEDLIST
, LB_SETCURSEL
, -1, 0);
321 SendDlgItemMessageW(hwnd
, IDC_XINPUTLIST
, LB_SETCURSEL
, -1, 0);
322 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONENABLE
), FALSE
);
323 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONDISABLE
), TRUE
);
324 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONOVERRIDE
), FALSE
);
325 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONRESET
), TRUE
);
329 SendDlgItemMessageW(hwnd
, IDC_JOYSTICKLIST
, LB_SETCURSEL
, -1, 0);
330 SendDlgItemMessageW(hwnd
, IDC_DISABLEDLIST
, LB_SETCURSEL
, -1, 0);
331 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONENABLE
), FALSE
);
332 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONDISABLE
), TRUE
);
333 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONOVERRIDE
), TRUE
);
334 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONRESET
), FALSE
);
337 case IDC_DISABLEDLIST
:
338 SendDlgItemMessageW(hwnd
, IDC_JOYSTICKLIST
, LB_SETCURSEL
, -1, 0);
339 SendDlgItemMessageW(hwnd
, IDC_XINPUTLIST
, LB_SETCURSEL
, -1, 0);
340 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONENABLE
), TRUE
);
341 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONDISABLE
), FALSE
);
342 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONOVERRIDE
), FALSE
);
343 EnableWindow(GetDlgItem(hwnd
, IDC_BUTTONRESET
), FALSE
);
359 /******************************************************************************
360 * propsheet_callback [internal]
362 static int CALLBACK
propsheet_callback(HWND hwnd
, UINT msg
, LPARAM lparam
)
364 TRACE("(%p, 0x%08x/%d, 0x%Ix)\n", hwnd
, msg
, msg
, lparam
);
367 case PSCB_INITIALIZED
:
373 static void display_cpl_sheets( HWND parent
)
375 INITCOMMONCONTROLSEX init
=
377 .dwSize
= sizeof(INITCOMMONCONTROLSEX
),
378 .dwICC
= ICC_LISTVIEW_CLASSES
| ICC_BAR_CLASSES
,
380 PROPSHEETPAGEW pages
[] =
383 .dwSize
= sizeof(PROPSHEETPAGEW
),
385 .pszTemplate
= MAKEINTRESOURCEW( IDD_LIST
),
386 .pfnDlgProc
= list_dlgproc
,
389 .dwSize
= sizeof(PROPSHEETPAGEW
),
391 .pszTemplate
= MAKEINTRESOURCEW( IDD_TEST_DI
),
392 .pfnDlgProc
= test_di_dialog_proc
,
395 .dwSize
= sizeof(PROPSHEETPAGEW
),
397 .pszTemplate
= MAKEINTRESOURCEW( IDD_TEST_XI
),
398 .pfnDlgProc
= test_xi_dialog_proc
,
401 PROPSHEETHEADERW header
=
403 .dwSize
= sizeof(PROPSHEETHEADERW
),
404 .dwFlags
= PSH_PROPSHEETPAGE
| PSH_USEICONID
| PSH_USECALLBACK
,
405 .hwndParent
= parent
,
407 .pszCaption
= MAKEINTRESOURCEW( IDS_CPL_NAME
),
408 .nPages
= ARRAY_SIZE(pages
),
410 .pfnCallback
= propsheet_callback
,
412 ACTCTXW context_desc
=
414 .cbSize
= sizeof(ACTCTXW
),
416 .lpResourceName
= MAKEINTRESOURCEW( 124 ),
417 .dwFlags
= ACTCTX_FLAG_HMODULE_VALID
| ACTCTX_FLAG_RESOURCE_NAME_VALID
,
423 OleInitialize( NULL
);
425 context
= CreateActCtxW( &context_desc
);
426 if (context
== INVALID_HANDLE_VALUE
) activated
= FALSE
;
427 else activated
= ActivateActCtx( context
, &cookie
);
429 InitCommonControlsEx( &init
);
430 PropertySheetW( &header
);
432 if (activated
) DeactivateActCtx( 0, cookie
);
433 ReleaseActCtx( context
);
437 static void register_window_class(void)
442 .lpfnWndProc
= &test_xi_window_proc
,
443 .lpszClassName
= L
"JoyCplXInput",
445 WNDCLASSW di_axes_class
=
448 .lpfnWndProc
= &test_di_axes_window_proc
,
449 .lpszClassName
= L
"JoyCplDInputAxes",
451 WNDCLASSW di_povs_class
=
454 .lpfnWndProc
= &test_di_povs_window_proc
,
455 .lpszClassName
= L
"JoyCplDInputPOVs",
457 WNDCLASSW di_buttons_class
=
460 .lpfnWndProc
= &test_di_buttons_window_proc
,
461 .lpszClassName
= L
"JoyCplDInputButtons",
464 RegisterClassW( &xi_class
);
465 RegisterClassW( &di_axes_class
);
466 RegisterClassW( &di_povs_class
);
467 RegisterClassW( &di_buttons_class
);
470 static void unregister_window_class(void)
472 UnregisterClassW( L
"JoyCplDInputAxes", hcpl
);
473 UnregisterClassW( L
"JoyCplDInputPOVs", hcpl
);
474 UnregisterClassW( L
"JoyCplDInputButtons", hcpl
);
475 UnregisterClassW( L
"JoyCplXInput", hcpl
);
478 /*********************************************************************
479 * CPlApplet (joy.cpl.@)
481 * Control Panel entry point
484 * hWnd [I] Handle for the Control Panel Window
485 * command [I] CPL_* Command
486 * lParam1 [I] first extra Parameter
487 * lParam2 [I] second extra Parameter
490 * Depends on the command
493 LONG CALLBACK
CPlApplet(HWND hwnd
, UINT command
, LPARAM lParam1
, LPARAM lParam2
)
495 TRACE("(%p, %u, 0x%Ix, 0x%Ix)\n", hwnd
, command
, lParam1
, lParam2
);
500 register_window_class();
508 CPLINFO
*appletInfo
= (CPLINFO
*) lParam2
;
510 appletInfo
->idIcon
= ICO_MAIN
;
511 appletInfo
->idName
= IDS_CPL_NAME
;
512 appletInfo
->idInfo
= IDS_CPL_INFO
;
513 appletInfo
->lData
= 0;
518 display_cpl_sheets( hwnd
);
523 unregister_window_class();