cmd: Backup echo mode before running external batch file.
[wine/multimedia.git] / dlls / dinput / config.c
blob1c6da6ccf2359e9643c858eb5503fe6e71b41d27
1 /*
2 * Copyright (c) 2011 Lucas Fialho Zawacki
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
19 #include "wine/debug.h"
20 #include "wine/unicode.h"
21 #include "objbase.h"
22 #include "dinput_private.h"
23 #include "device_private.h"
24 #include "resource.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
28 typedef struct {
29 int nobjects;
30 IDirectInputDevice8W *lpdid;
31 DIDEVICEINSTANCEW ddi;
32 DIDEVICEOBJECTINSTANCEW ddo[256];
33 } DeviceData;
35 typedef struct {
36 int ndevices;
37 DeviceData *devices;
38 } DIDevicesData;
40 typedef struct {
41 IDirectInput8W *lpDI;
42 LPDIACTIONFORMATW lpdiaf;
43 LPDIACTIONFORMATW original_lpdiaf;
44 DIDevicesData devices_data;
45 int display_only;
46 } ConfigureDevicesData;
49 * Enumeration callback functions
51 static BOOL CALLBACK collect_objects(LPCDIDEVICEOBJECTINSTANCEW lpddo, LPVOID pvRef)
53 DeviceData *data = (DeviceData*) pvRef;
55 data->ddo[data->nobjects] = *lpddo;
57 data->nobjects++;
58 return DIENUM_CONTINUE;
61 static BOOL CALLBACK count_devices(LPCDIDEVICEINSTANCEW lpddi, IDirectInputDevice8W *lpdid, DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef)
63 DIDevicesData *data = (DIDevicesData*) pvRef;
65 data->ndevices++;
66 return DIENUM_CONTINUE;
69 static BOOL CALLBACK collect_devices(LPCDIDEVICEINSTANCEW lpddi, IDirectInputDevice8W *lpdid, DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef)
71 DIDevicesData *data = (DIDevicesData*) pvRef;
72 DeviceData *device = &data->devices[data->ndevices];
73 device->lpdid = lpdid;
74 device->ddi = *lpddi;
76 IDirectInputDevice_AddRef(lpdid);
78 device->nobjects = 0;
79 IDirectInputDevice_EnumObjects(lpdid, collect_objects, (LPVOID) device, DIDFT_ALL);
81 data->ndevices++;
82 return DIENUM_CONTINUE;
86 * Listview utility functions
88 static void init_listview_columns(HWND dialog)
90 HINSTANCE hinstance = (HINSTANCE) GetWindowLongPtrW(dialog, GWLP_HINSTANCE);
91 LVCOLUMNW listColumn;
92 RECT viewRect;
93 int width;
94 WCHAR column[MAX_PATH];
96 GetClientRect(GetDlgItem(dialog, IDC_DEVICEOBJECTSLIST), &viewRect);
97 width = (viewRect.right - viewRect.left)/2;
99 LoadStringW(hinstance, IDS_OBJECTCOLUMN, column, sizeof(column)/sizeof(column[0]));
100 listColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
101 listColumn.pszText = column;
102 listColumn.cchTextMax = lstrlenW(listColumn.pszText);
103 listColumn.cx = width;
105 SendDlgItemMessageW (dialog, IDC_DEVICEOBJECTSLIST, LVM_INSERTCOLUMNW, 0, (LPARAM) &listColumn);
107 LoadStringW(hinstance, IDS_ACTIONCOLUMN, column, sizeof(column)/sizeof(column[0]));
108 listColumn.cx = width;
109 listColumn.pszText = column;
110 listColumn.cchTextMax = lstrlenW(listColumn.pszText);
112 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_INSERTCOLUMNW, 1, (LPARAM) &listColumn);
115 static int lv_get_cur_item(HWND dialog)
117 return SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
120 static int lv_get_item_data(HWND dialog, int index)
122 LVITEMW item;
124 if (index < 0) return -1;
126 item.mask = LVIF_PARAM;
127 item.iItem = index;
128 item.iSubItem = 0;
130 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_GETITEMW , 0, (LPARAM)&item);
132 return item.lParam;
135 static void lv_set_action(HWND dialog, int item, int action, LPDIACTIONFORMATW lpdiaf)
137 static const WCHAR no_action[] = {'-','\0'};
138 const WCHAR *action_text = no_action;
139 LVITEMW lvItem;
141 if (item < 0) return;
143 if (action != -1)
144 action_text = lpdiaf->rgoAction[action].lptszActionName;
146 /* Keep the action and text in the listview item */
147 lvItem.iItem = item;
149 lvItem.mask = LVIF_PARAM;
150 lvItem.iSubItem = 0;
151 lvItem.lParam = (LPARAM) action;
153 /* Action index */
154 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_SETITEMW, 0, (LPARAM) &lvItem);
156 lvItem.mask = LVIF_TEXT;
157 lvItem.iSubItem = 1;
158 lvItem.pszText = (WCHAR *)action_text;
159 lvItem.cchTextMax = lstrlenW(lvItem.pszText);
161 /* Text */
162 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_SETITEMW, 0, (LPARAM) &lvItem);
166 * Utility functions
168 static DeviceData* get_cur_device(HWND dialog)
170 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
171 int sel = SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_GETCURSEL, 0, 0);
172 return &data->devices_data.devices[sel];
175 static LPDIACTIONFORMATW get_cur_lpdiaf(HWND dialog)
177 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
178 return data->lpdiaf;
181 static int dialog_display_only(HWND dialog)
183 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
184 return data->display_only;
187 static void init_devices(HWND dialog, IDirectInput8W *lpDI, DIDevicesData *data, LPDIACTIONFORMATW lpdiaf)
189 int i;
191 /* Count devices */
192 IDirectInput8_EnumDevicesBySemantics(lpDI, NULL, lpdiaf, count_devices, (LPVOID) data, 0);
194 /* Allocate devices */
195 data->devices = (DeviceData*) HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceData) * data->ndevices);
197 /* Collect and insert */
198 data->ndevices = 0;
199 IDirectInput8_EnumDevicesBySemantics(lpDI, NULL, lpdiaf, collect_devices, (LPVOID) data, 0);
201 for (i=0; i < data->ndevices; i++)
202 SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_ADDSTRING, 0, (LPARAM) data->devices[i].ddi.tszProductName );
205 static void destroy_data(HWND dialog)
207 int i;
208 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
209 DIDevicesData *devices_data = &data->devices_data;
211 /* Free the devices */
212 for (i=0; i < devices_data->ndevices; i++)
213 IDirectInputDevice8_Release(devices_data->devices[i].lpdid);
215 HeapFree(GetProcessHeap(), 0, devices_data->devices);
217 /* Free the backup LPDIACTIONFORMATW */
218 HeapFree(GetProcessHeap(), 0, data->original_lpdiaf->rgoAction);
219 HeapFree(GetProcessHeap(), 0, data->original_lpdiaf);
222 static void fill_device_object_list(HWND dialog)
224 DeviceData *device = get_cur_device(dialog);
225 LPDIACTIONFORMATW lpdiaf = get_cur_lpdiaf(dialog);
226 LVITEMW item;
227 int i, j;
229 /* Clean the listview */
230 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_DELETEALLITEMS, 0, 0);
232 /* Add each object */
233 for (i=0; i < device->nobjects; i++)
235 int action = -1;
237 item.mask = LVIF_TEXT | LVIF_PARAM;
238 item.iItem = i;
239 item.iSubItem = 0;
240 item.pszText = device->ddo[i].tszName;
241 item.cchTextMax = lstrlenW(item.pszText);
243 /* Add the item */
244 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_INSERTITEMW, 0, (LPARAM) &item);
246 /* Search for an assigned action for this device */
247 for (j=0; j < lpdiaf->dwNumActions; j++)
249 if (IsEqualGUID(&lpdiaf->rgoAction[j].guidInstance, &device->ddi.guidInstance) &&
250 lpdiaf->rgoAction[j].dwObjID == device->ddo[i].dwType)
252 action = j;
253 break;
257 lv_set_action(dialog, i, action, lpdiaf);
261 static void show_suitable_actions(HWND dialog)
263 DeviceData *device = get_cur_device(dialog);
264 LPDIACTIONFORMATW lpdiaf = get_cur_lpdiaf(dialog);
265 int i, added = 0;
266 int obj = lv_get_cur_item(dialog);
268 if (obj < 0) return;
270 SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_RESETCONTENT, 0, 0);
272 for (i=0; i < lpdiaf->dwNumActions; i++)
274 /* Skip keyboard actions for non keyboards */
275 if (GET_DIDEVICE_TYPE(device->ddi.dwDevType) != DI8DEVTYPE_KEYBOARD &&
276 (lpdiaf->rgoAction[i].dwSemantic & DIKEYBOARD_MASK) == DIKEYBOARD_MASK) continue;
278 /* Skip mouse actions for non mouses */
279 if (GET_DIDEVICE_TYPE(device->ddi.dwDevType) != DI8DEVTYPE_MOUSE &&
280 (lpdiaf->rgoAction[i].dwSemantic & DIMOUSE_MASK) == DIMOUSE_MASK) continue;
282 /* Add action string and index in the action format to the list entry */
283 if (DIDFT_GETINSTANCE(lpdiaf->rgoAction[i].dwSemantic) & DIDFT_GETTYPE(device->ddo[obj].dwType))
285 SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_ADDSTRING, 0, (LPARAM)lpdiaf->rgoAction[i].lptszActionName);
286 SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_SETITEMDATA, added, (LPARAM) i);
287 added++;
292 static void assign_action(HWND dialog)
294 DeviceData *device = get_cur_device(dialog);
295 LPDIACTIONFORMATW lpdiaf = get_cur_lpdiaf(dialog);
296 LVFINDINFOW lvFind;
297 int sel = SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_GETCURSEL, 0, 0);
298 int action = SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_GETITEMDATA, sel, 0);
299 int obj = lv_get_cur_item(dialog);
300 int old_action = lv_get_item_data(dialog, obj);
301 int used_obj;
303 DIDEVICEOBJECTINSTANCEW ddo = device->ddo[obj];
305 if (old_action == action) return;
307 /* Clear old action */
308 if (old_action != -1)
310 lpdiaf->rgoAction[old_action].dwObjID = 0;
311 lpdiaf->rgoAction[old_action].guidInstance = GUID_NULL;
312 lpdiaf->rgoAction[old_action].dwHow = DIAH_UNMAPPED;
315 /* Find if action text is already set for other object and unset it */
316 lvFind.flags = LVFI_PARAM;
317 lvFind.lParam = action;
319 used_obj = SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_FINDITEMW, -1, (LPARAM) &lvFind);
321 lv_set_action(dialog, used_obj, -1, lpdiaf);
323 /* Set new action */
324 lpdiaf->rgoAction[action].dwObjID = ddo.dwType;
325 lpdiaf->rgoAction[action].guidInstance = device->ddi.guidInstance;
326 lpdiaf->rgoAction[action].dwHow = DIAH_USERCONFIG;
328 /* Set new action in the list */
329 lv_set_action(dialog, obj, action, lpdiaf);
332 static void copy_actions(LPDIACTIONFORMATW to, LPDIACTIONFORMATW from)
334 int i;
335 for (i=0; i < from->dwNumActions; i++)
337 to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
338 to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
339 to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
340 to->rgoAction[i].lptszActionName = from->rgoAction[i].lptszActionName;
344 static void reset_actions(HWND dialog)
346 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
347 LPDIACTIONFORMATW to = data->lpdiaf, from = data->original_lpdiaf;
349 copy_actions(to, from);
352 static INT_PTR CALLBACK ConfigureDevicesDlgProc(HWND dialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
354 switch(uMsg)
356 case WM_INITDIALOG:
358 ConfigureDevicesData *data = (ConfigureDevicesData*) lParam;
360 /* Initialize action format and enumerate devices */
361 init_devices(dialog, data->lpDI, &data->devices_data, data->lpdiaf);
363 /* Store information in the window */
364 SetWindowLongPtrW(dialog, DWLP_USER, (LONG_PTR) data);
366 init_listview_columns(dialog);
368 /* Create a backup action format for CANCEL and RESET operations */
369 data->original_lpdiaf = HeapAlloc(GetProcessHeap(), 0, sizeof(LPDIACTIONFORMATW));
370 data->original_lpdiaf->dwNumActions = data->lpdiaf->dwNumActions;
371 data->original_lpdiaf->rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*data->lpdiaf->dwNumActions);
372 copy_actions(data->original_lpdiaf, data->lpdiaf);
374 break;
377 case WM_NOTIFY:
379 switch (((LPNMHDR)lParam)->code)
381 case LVN_ITEMCHANGED:
382 show_suitable_actions(dialog);
383 break;
385 break;
388 case WM_COMMAND:
390 switch(LOWORD(wParam))
393 case IDC_ACTIONLIST:
395 switch (HIWORD(wParam))
397 case LBN_DBLCLK:
398 /* Ignore this if app did not ask for editing */
399 if (dialog_display_only(dialog)) break;
401 assign_action(dialog);
402 break;
404 break;
406 case IDC_CONTROLLERCOMBO:
408 switch (HIWORD(wParam))
410 case CBN_SELCHANGE:
411 fill_device_object_list(dialog);
412 break;
414 break;
416 case IDOK:
417 EndDialog(dialog, 0);
418 destroy_data(dialog);
419 break;
421 case IDCANCEL:
422 reset_actions(dialog);
423 EndDialog(dialog, 0);
424 destroy_data(dialog);
425 break;
427 case IDC_RESET:
428 reset_actions(dialog);
429 fill_device_object_list(dialog);
430 break;
432 break;
435 return FALSE;
438 HRESULT _configure_devices(IDirectInput8W *iface,
439 LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
440 LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,
441 DWORD dwFlags,
442 LPVOID pvRefData
445 ConfigureDevicesData data;
446 data.lpDI = iface;
447 data.lpdiaf = lpdiCDParams->lprgFormats;
448 data.display_only = !(dwFlags & DICD_EDIT);
450 InitCommonControls();
452 DialogBoxParamW(GetModuleHandleA("dinput.dll"), (LPCWSTR) MAKEINTRESOURCE(IDD_CONFIGUREDEVICES), lpdiCDParams->hwnd, ConfigureDevicesDlgProc, (LPARAM) &data);
454 return DI_OK;