ntdll: Use a separate memory allocation for the kernel stack.
[wine.git] / dlls / joy.cpl / main.c
blob28334ec6f99baf264c15685db7884aa3ebd3390e
1 /*
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
22 #define COBJMACROS
23 #define CONST_VTABLE
25 #include <stdarg.h>
26 #include <windef.h>
27 #include <winbase.h>
28 #include <winuser.h>
29 #include <commctrl.h>
30 #include <dinput.h>
31 #include <cpl.h>
32 #include "ole2.h"
34 #include "wine/debug.h"
35 #include "wine/list.h"
37 #include "joy_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(joycpl);
41 struct device
43 struct list entry;
44 IDirectInputDevice8W *device;
47 static HMODULE hcpl;
49 static CRITICAL_SECTION joy_cs;
50 static CRITICAL_SECTION_DEBUG joy_cs_debug =
52 0, 0, &joy_cs,
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 /*********************************************************************
61 * DllMain
63 BOOL WINAPI DllMain(HINSTANCE hdll, DWORD reason, LPVOID reserved)
65 TRACE("(%p, %ld, %p)\n", hdll, reason, reserved);
67 switch (reason)
69 case DLL_PROCESS_ATTACH:
70 DisableThreadLibraryCalls(hdll);
71 hcpl = hdll;
73 return TRUE;
76 static BOOL CALLBACK enum_devices( const DIDEVICEINSTANCEW *instance, void *context )
78 DIDEVCAPS caps = {.dwSize = sizeof(DIDEVCAPS)};
79 IDirectInput8W *dinput = context;
80 struct device *entry;
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 );
102 free( entry );
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)
112 *appkey = 0;
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))
117 *defkey = 0;
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)
128 if (value == NULL)
130 if (appkey && !RegDeleteValueW(appkey, name))
131 return 0;
133 if (defkey && !RegDeleteValueW(defkey, name))
134 return 0;
136 else
138 if (appkey && !RegSetValueExW(appkey, name, 0, REG_SZ, (const BYTE*) value, (size + 1)*sizeof(WCHAR)))
139 return 0;
141 if (defkey && !RegSetValueExW(defkey, name, 0, REG_SZ, (const BYTE*) value, (size + 1)*sizeof(WCHAR)))
142 return 0;
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)
155 HKEY hkey, appkey;
157 get_app_key(&hkey, &appkey);
159 if (!enable)
160 set_config_key(hkey, appkey, joy_name, L"disabled", wcslen(L"disabled"));
161 else
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;
172 HKEY hkey, appkey;
173 DWORD values = 0;
174 LSTATUS status;
175 DWORD i;
177 clear_devices();
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 =
192 .diph =
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)
228 HKEY hkey, appkey;
230 get_app_key(&hkey, &appkey);
232 if (override)
233 set_config_key(hkey, appkey, joy_name, L"override", wcslen(L"override"));
234 else
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};
248 int sel;
250 TRACE("(%p, 0x%08x/%d, 0x%Ix)\n", hwnd, msg, msg, lparam);
251 switch (msg)
253 case WM_INITDIALOG:
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);
262 return TRUE;
265 case WM_COMMAND:
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 );
282 break;
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 );
295 break;
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 );
306 break;
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 );
317 break;
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);
326 break;
328 case IDC_XINPUTLIST:
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);
335 break;
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);
344 break;
347 return TRUE;
349 case WM_NOTIFY:
350 return TRUE;
352 default:
353 break;
355 return 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);
365 switch (msg)
367 case PSCB_INITIALIZED:
368 break;
370 return 0;
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),
384 .hInstance = hcpl,
385 .pszTemplate = MAKEINTRESOURCEW( IDD_LIST ),
386 .pfnDlgProc = list_dlgproc,
389 .dwSize = sizeof(PROPSHEETPAGEW),
390 .hInstance = hcpl,
391 .pszTemplate = MAKEINTRESOURCEW( IDD_TEST_DI ),
392 .pfnDlgProc = test_di_dialog_proc,
395 .dwSize = sizeof(PROPSHEETPAGEW),
396 .hInstance = hcpl,
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,
406 .hInstance = hcpl,
407 .pszCaption = MAKEINTRESOURCEW( IDS_CPL_NAME ),
408 .nPages = ARRAY_SIZE(pages),
409 .ppsp = pages,
410 .pfnCallback = propsheet_callback,
412 ACTCTXW context_desc =
414 .cbSize = sizeof(ACTCTXW),
415 .hModule = hcpl,
416 .lpResourceName = MAKEINTRESOURCEW( 124 ),
417 .dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID,
419 ULONG_PTR cookie;
420 HANDLE context;
421 BOOL activated;
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 );
434 OleUninitialize();
437 static void register_window_class(void)
439 WNDCLASSW xi_class =
441 .hInstance = hcpl,
442 .lpfnWndProc = &test_xi_window_proc,
443 .lpszClassName = L"JoyCplXInput",
445 WNDCLASSW di_axes_class =
447 .hInstance = hcpl,
448 .lpfnWndProc = &test_di_axes_window_proc,
449 .lpszClassName = L"JoyCplDInputAxes",
451 WNDCLASSW di_povs_class =
453 .hInstance = hcpl,
454 .lpfnWndProc = &test_di_povs_window_proc,
455 .lpszClassName = L"JoyCplDInputPOVs",
457 WNDCLASSW di_buttons_class =
459 .hInstance = hcpl,
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
483 * PARAMS
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
489 * RETURNS
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);
497 switch (command)
499 case CPL_INIT:
500 register_window_class();
501 return TRUE;
503 case CPL_GETCOUNT:
504 return 1;
506 case CPL_INQUIRE:
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;
514 return TRUE;
517 case CPL_DBLCLK:
518 display_cpl_sheets( hwnd );
519 break;
521 case CPL_STOP:
522 clear_devices();
523 unregister_window_class();
524 break;
527 return FALSE;