mf/tests: Clobber the alignment and bytes per second, to test if the DMO fixes it.
[wine.git] / dlls / dinput / config.c
blobd7a416501f0cdb688c37dc3ddbc3a5b39c6866c8
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 "objbase.h"
21 #include "dinput_private.h"
22 #include "device_private.h"
23 #include "resource.h"
25 typedef struct {
26 int nobjects;
27 IDirectInputDevice8W *lpdid;
28 DIDEVICEINSTANCEW ddi;
29 DIDEVICEOBJECTINSTANCEW ddo[256];
30 } DeviceData;
32 typedef struct {
33 int ndevices;
34 DeviceData *devices;
35 } DIDevicesData;
37 typedef struct {
38 IDirectInput8W *lpDI;
39 LPDIACTIONFORMATW lpdiaf;
40 LPDIACTIONFORMATW original_lpdiaf;
41 DIDevicesData devices_data;
42 int display_only;
43 } ConfigureDevicesData;
46 * Enumeration callback functions
48 static BOOL CALLBACK collect_objects(LPCDIDEVICEOBJECTINSTANCEW lpddo, LPVOID pvRef)
50 DeviceData *data = (DeviceData*) pvRef;
52 data->ddo[data->nobjects] = *lpddo;
54 data->nobjects++;
55 return DIENUM_CONTINUE;
58 static BOOL CALLBACK count_devices(LPCDIDEVICEINSTANCEW lpddi, IDirectInputDevice8W *lpdid, DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef)
60 DIDevicesData *data = (DIDevicesData*) pvRef;
62 data->ndevices++;
63 return DIENUM_CONTINUE;
66 static BOOL CALLBACK collect_devices(LPCDIDEVICEINSTANCEW lpddi, IDirectInputDevice8W *lpdid, DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef)
68 DIDevicesData *data = (DIDevicesData*) pvRef;
69 DeviceData *device = &data->devices[data->ndevices];
70 device->lpdid = lpdid;
71 device->ddi = *lpddi;
73 IDirectInputDevice_AddRef(lpdid);
75 device->nobjects = 0;
76 IDirectInputDevice_EnumObjects(lpdid, collect_objects, (LPVOID) device, DIDFT_ALL);
78 data->ndevices++;
79 return DIENUM_CONTINUE;
83 * Listview utility functions
85 static void init_listview_columns(HWND dialog)
87 LVCOLUMNW listColumn;
88 RECT viewRect;
89 int width;
90 WCHAR column[MAX_PATH];
92 GetClientRect(GetDlgItem(dialog, IDC_DEVICEOBJECTSLIST), &viewRect);
93 width = (viewRect.right - viewRect.left)/2;
95 LoadStringW(DINPUT_instance, IDS_OBJECTCOLUMN, column, ARRAY_SIZE(column));
96 listColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
97 listColumn.pszText = column;
98 listColumn.cchTextMax = wcslen( listColumn.pszText );
99 listColumn.cx = width;
101 SendDlgItemMessageW (dialog, IDC_DEVICEOBJECTSLIST, LVM_INSERTCOLUMNW, 0, (LPARAM) &listColumn);
103 LoadStringW(DINPUT_instance, IDS_ACTIONCOLUMN, column, ARRAY_SIZE(column));
104 listColumn.cx = width;
105 listColumn.pszText = column;
106 listColumn.cchTextMax = wcslen( listColumn.pszText );
108 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_INSERTCOLUMNW, 1, (LPARAM) &listColumn);
111 static int lv_get_cur_item(HWND dialog)
113 return SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
116 static int lv_get_item_data(HWND dialog, int index)
118 LVITEMW item;
120 if (index < 0) return -1;
122 item.mask = LVIF_PARAM;
123 item.iItem = index;
124 item.iSubItem = 0;
126 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_GETITEMW , 0, (LPARAM)&item);
128 return item.lParam;
131 static void lv_set_action(HWND dialog, int item, int action, LPDIACTIONFORMATW lpdiaf)
133 const WCHAR *action_text = L"-";
134 LVITEMW lvItem;
136 if (item < 0) return;
138 if (action != -1)
139 action_text = lpdiaf->rgoAction[action].lptszActionName;
141 /* Keep the action and text in the listview item */
142 lvItem.iItem = item;
144 lvItem.mask = LVIF_PARAM;
145 lvItem.iSubItem = 0;
146 lvItem.lParam = (LPARAM) action;
148 /* Action index */
149 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_SETITEMW, 0, (LPARAM) &lvItem);
151 lvItem.mask = LVIF_TEXT;
152 lvItem.iSubItem = 1;
153 lvItem.pszText = (WCHAR *)action_text;
154 lvItem.cchTextMax = wcslen( lvItem.pszText );
156 /* Text */
157 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_SETITEMW, 0, (LPARAM) &lvItem);
161 * Utility functions
163 static DeviceData* get_cur_device(HWND dialog)
165 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
166 int sel = SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_GETCURSEL, 0, 0);
167 return &data->devices_data.devices[sel];
170 static LPDIACTIONFORMATW get_cur_lpdiaf(HWND dialog)
172 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
173 return data->lpdiaf;
176 static int dialog_display_only(HWND dialog)
178 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
179 return data->display_only;
182 static void init_devices(HWND dialog, IDirectInput8W *lpDI, DIDevicesData *data, LPDIACTIONFORMATW lpdiaf)
184 int i;
186 /* Count devices */
187 data->ndevices = 0;
188 IDirectInput8_EnumDevicesBySemantics(lpDI, NULL, lpdiaf, count_devices, (LPVOID) data, 0);
190 /* Allocate devices */
191 data->devices = malloc( sizeof(DeviceData) * data->ndevices );
193 /* Collect and insert */
194 data->ndevices = 0;
195 IDirectInput8_EnumDevicesBySemantics(lpDI, NULL, lpdiaf, collect_devices, (LPVOID) data, 0);
197 for (i=0; i < data->ndevices; i++)
198 SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_ADDSTRING, 0, (LPARAM) data->devices[i].ddi.tszProductName );
201 static void destroy_data(HWND dialog)
203 int i;
204 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
205 DIDevicesData *devices_data = &data->devices_data;
207 /* Free the devices */
208 for (i=0; i < devices_data->ndevices; i++)
209 IDirectInputDevice8_Release(devices_data->devices[i].lpdid);
211 free( devices_data->devices );
213 /* Free the backup LPDIACTIONFORMATW */
214 free( data->original_lpdiaf->rgoAction );
215 free( data->original_lpdiaf );
218 static void fill_device_object_list(HWND dialog)
220 DeviceData *device = get_cur_device(dialog);
221 LPDIACTIONFORMATW lpdiaf = get_cur_lpdiaf(dialog);
222 LVITEMW item;
223 int i, j;
225 /* Clean the listview */
226 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_DELETEALLITEMS, 0, 0);
228 /* Add each object */
229 for (i=0; i < device->nobjects; i++)
231 int action = -1;
233 item.mask = LVIF_TEXT | LVIF_PARAM;
234 item.iItem = i;
235 item.iSubItem = 0;
236 item.pszText = device->ddo[i].tszName;
237 item.cchTextMax = wcslen( item.pszText );
239 /* Add the item */
240 SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_INSERTITEMW, 0, (LPARAM) &item);
242 /* Search for an assigned action for this device */
243 for (j=0; j < lpdiaf->dwNumActions; j++)
245 if (IsEqualGUID(&lpdiaf->rgoAction[j].guidInstance, &device->ddi.guidInstance) &&
246 lpdiaf->rgoAction[j].dwObjID == device->ddo[i].dwType)
248 action = j;
249 break;
253 lv_set_action(dialog, i, action, lpdiaf);
257 static void show_suitable_actions(HWND dialog)
259 DeviceData *device = get_cur_device(dialog);
260 LPDIACTIONFORMATW lpdiaf = get_cur_lpdiaf(dialog);
261 int i, added = 0;
262 int obj = lv_get_cur_item(dialog);
264 if (obj < 0) return;
266 SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_RESETCONTENT, 0, 0);
268 for (i=0; i < lpdiaf->dwNumActions; i++)
270 /* Skip keyboard actions for non keyboards */
271 if (GET_DIDEVICE_TYPE(device->ddi.dwDevType) != DI8DEVTYPE_KEYBOARD &&
272 (lpdiaf->rgoAction[i].dwSemantic & DIKEYBOARD_MASK) == DIKEYBOARD_MASK) continue;
274 /* Skip mouse actions for non mouses */
275 if (GET_DIDEVICE_TYPE(device->ddi.dwDevType) != DI8DEVTYPE_MOUSE &&
276 (lpdiaf->rgoAction[i].dwSemantic & DIMOUSE_MASK) == DIMOUSE_MASK) continue;
278 /* Add action string and index in the action format to the list entry */
279 if (DIDFT_GETINSTANCE(lpdiaf->rgoAction[i].dwSemantic) & DIDFT_GETTYPE(device->ddo[obj].dwType))
281 SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_ADDSTRING, 0, (LPARAM)lpdiaf->rgoAction[i].lptszActionName);
282 SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_SETITEMDATA, added, (LPARAM) i);
283 added++;
288 static void assign_action(HWND dialog)
290 DeviceData *device = get_cur_device(dialog);
291 LPDIACTIONFORMATW lpdiaf = get_cur_lpdiaf(dialog);
292 LVFINDINFOW lvFind;
293 int sel = SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_GETCURSEL, 0, 0);
294 int action = SendDlgItemMessageW(dialog, IDC_ACTIONLIST, LB_GETITEMDATA, sel, 0);
295 int obj = lv_get_cur_item(dialog);
296 int old_action = lv_get_item_data(dialog, obj);
297 int used_obj;
298 DWORD type;
300 if (old_action == action) return;
301 if (obj < 0) return;
302 type = device->ddo[obj].dwType;
304 /* Clear old action */
305 if (old_action != -1)
307 lpdiaf->rgoAction[old_action].dwObjID = 0;
308 lpdiaf->rgoAction[old_action].guidInstance = GUID_NULL;
309 lpdiaf->rgoAction[old_action].dwHow = DIAH_UNMAPPED;
312 /* Find if action text is already set for other object and unset it */
313 lvFind.flags = LVFI_PARAM;
314 lvFind.lParam = action;
316 used_obj = SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_FINDITEMW, -1, (LPARAM) &lvFind);
318 lv_set_action(dialog, used_obj, -1, lpdiaf);
320 /* Set new action */
321 lpdiaf->rgoAction[action].dwObjID = type;
322 lpdiaf->rgoAction[action].guidInstance = device->ddi.guidInstance;
323 lpdiaf->rgoAction[action].dwHow = DIAH_USERCONFIG;
325 /* Set new action in the list */
326 lv_set_action(dialog, obj, action, lpdiaf);
329 static void copy_actions(LPDIACTIONFORMATW to, LPDIACTIONFORMATW from)
331 DWORD i;
332 for (i=0; i < from->dwNumActions; i++)
334 to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
335 to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
336 to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
337 to->rgoAction[i].lptszActionName = from->rgoAction[i].lptszActionName;
341 static void reset_actions(HWND dialog)
343 ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
344 LPDIACTIONFORMATW to = data->lpdiaf, from = data->original_lpdiaf;
346 copy_actions(to, from);
349 static INT_PTR CALLBACK ConfigureDevicesDlgProc(HWND dialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
351 switch(uMsg)
353 case WM_INITDIALOG:
355 ConfigureDevicesData *data = (ConfigureDevicesData*) lParam;
357 /* Initialize action format and enumerate devices */
358 init_devices(dialog, data->lpDI, &data->devices_data, data->lpdiaf);
360 /* Store information in the window */
361 SetWindowLongPtrW(dialog, DWLP_USER, (LONG_PTR) data);
363 init_listview_columns(dialog);
365 /* Create a backup action format for CANCEL and RESET operations */
366 data->original_lpdiaf = malloc( sizeof(*data->original_lpdiaf) );
367 data->original_lpdiaf->dwNumActions = data->lpdiaf->dwNumActions;
368 data->original_lpdiaf->rgoAction = malloc( sizeof(DIACTIONW) * data->lpdiaf->dwNumActions );
369 copy_actions(data->original_lpdiaf, data->lpdiaf);
371 /* Select the first device and show its actions */
372 SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_SETCURSEL, 0, 0);
373 fill_device_object_list(dialog);
375 ShowCursor(TRUE);
377 break;
380 case WM_DESTROY:
381 ShowCursor(FALSE);
382 break;
384 case WM_NOTIFY:
386 switch (((LPNMHDR)lParam)->code)
388 case LVN_ITEMCHANGED:
389 show_suitable_actions(dialog);
390 break;
392 break;
395 case WM_COMMAND:
397 switch(LOWORD(wParam))
400 case IDC_ACTIONLIST:
402 switch (HIWORD(wParam))
404 case LBN_DBLCLK:
405 /* Ignore this if app did not ask for editing */
406 if (dialog_display_only(dialog)) break;
408 assign_action(dialog);
409 break;
411 break;
413 case IDC_CONTROLLERCOMBO:
415 switch (HIWORD(wParam))
417 case CBN_SELCHANGE:
418 fill_device_object_list(dialog);
419 break;
421 break;
423 case IDOK:
424 EndDialog(dialog, 0);
425 destroy_data(dialog);
426 break;
428 case IDCANCEL:
429 reset_actions(dialog);
430 EndDialog(dialog, 0);
431 destroy_data(dialog);
432 break;
434 case IDC_RESET:
435 reset_actions(dialog);
436 fill_device_object_list(dialog);
437 break;
439 break;
442 return FALSE;
445 HRESULT _configure_devices(IDirectInput8W *iface,
446 LPDICONFIGUREDEVICESCALLBACK lpdiCallback,
447 LPDICONFIGUREDEVICESPARAMSW lpdiCDParams,
448 DWORD dwFlags,
449 LPVOID pvRefData
452 ConfigureDevicesData data;
453 data.lpDI = iface;
454 data.lpdiaf = lpdiCDParams->lprgFormats;
455 data.display_only = !(dwFlags & DICD_EDIT);
457 InitCommonControls();
459 DialogBoxParamW(DINPUT_instance, (const WCHAR *)MAKEINTRESOURCE(IDD_CONFIGUREDEVICES),
460 lpdiCDParams->hwnd, ConfigureDevicesDlgProc, (LPARAM)&data);
462 return DI_OK;