[DINPUT] Sync with Wine 3.0. CORE-14225
[reactos.git] / dll / directx / wine / dinput / device.c
1 /* DirectInput Device
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 *
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 /* This file contains all the Device specific functions that can be used as stubs
23 by real device implementations.
24
25 It also contains all the helper functions.
26 */
27
28 #include "dinput_private.h"
29
30 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
31 {
32 return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface);
33 }
34 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
35 {
36 return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface);
37 }
38
39 static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(IDirectInputDeviceImpl *This)
40 {
41 return &This->IDirectInputDevice8A_iface;
42 }
43 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(IDirectInputDeviceImpl *This)
44 {
45 return &This->IDirectInputDevice8W_iface;
46 }
47
48 /******************************************************************************
49 * Various debugging tools
50 */
51 static void _dump_cooperativelevel_DI(DWORD dwFlags) {
52 if (TRACE_ON(dinput)) {
53 unsigned int i;
54 static const struct {
55 DWORD mask;
56 const char *name;
57 } flags[] = {
58 #define FE(x) { x, #x}
59 FE(DISCL_BACKGROUND),
60 FE(DISCL_EXCLUSIVE),
61 FE(DISCL_FOREGROUND),
62 FE(DISCL_NONEXCLUSIVE),
63 FE(DISCL_NOWINKEY)
64 #undef FE
65 };
66 TRACE(" cooperative level : ");
67 for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
68 if (flags[i].mask & dwFlags)
69 TRACE("%s ",flags[i].name);
70 TRACE("\n");
71 }
72 }
73
74 static void _dump_ObjectDataFormat_flags(DWORD dwFlags) {
75 unsigned int i;
76 static const struct {
77 DWORD mask;
78 const char *name;
79 } flags[] = {
80 #define FE(x) { x, #x}
81 FE(DIDOI_FFACTUATOR),
82 FE(DIDOI_FFEFFECTTRIGGER),
83 FE(DIDOI_POLLED),
84 FE(DIDOI_GUIDISUSAGE)
85 #undef FE
86 };
87
88 if (!dwFlags) return;
89
90 TRACE("Flags:");
91
92 /* First the flags */
93 for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) {
94 if (flags[i].mask & dwFlags)
95 TRACE(" %s",flags[i].name);
96 }
97
98 /* Now specific values */
99 #define FE(x) case x: TRACE(" "#x); break
100 switch (dwFlags & DIDOI_ASPECTMASK) {
101 FE(DIDOI_ASPECTACCEL);
102 FE(DIDOI_ASPECTFORCE);
103 FE(DIDOI_ASPECTPOSITION);
104 FE(DIDOI_ASPECTVELOCITY);
105 }
106 #undef FE
107
108 }
109
110 static void _dump_EnumObjects_flags(DWORD dwFlags) {
111 if (TRACE_ON(dinput)) {
112 unsigned int i;
113 DWORD type, instance;
114 static const struct {
115 DWORD mask;
116 const char *name;
117 } flags[] = {
118 #define FE(x) { x, #x}
119 FE(DIDFT_RELAXIS),
120 FE(DIDFT_ABSAXIS),
121 FE(DIDFT_PSHBUTTON),
122 FE(DIDFT_TGLBUTTON),
123 FE(DIDFT_POV),
124 FE(DIDFT_COLLECTION),
125 FE(DIDFT_NODATA),
126 FE(DIDFT_FFACTUATOR),
127 FE(DIDFT_FFEFFECTTRIGGER),
128 FE(DIDFT_OUTPUT),
129 FE(DIDFT_VENDORDEFINED),
130 FE(DIDFT_ALIAS),
131 FE(DIDFT_OPTIONAL)
132 #undef FE
133 };
134 type = (dwFlags & 0xFF0000FF);
135 instance = ((dwFlags >> 8) & 0xFFFF);
136 TRACE("Type:");
137 if (type == DIDFT_ALL) {
138 TRACE(" DIDFT_ALL");
139 } else {
140 for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) {
141 if (flags[i].mask & type) {
142 type &= ~flags[i].mask;
143 TRACE(" %s",flags[i].name);
144 }
145 }
146 if (type) {
147 TRACE(" (unhandled: %08x)", type);
148 }
149 }
150 TRACE(" / Instance: ");
151 if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) {
152 TRACE("DIDFT_ANYINSTANCE");
153 } else {
154 TRACE("%3d", instance);
155 }
156 }
157 }
158
159 void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) {
160 if (TRACE_ON(dinput)) {
161 TRACE(" - dwObj = 0x%08x\n", diph->dwObj);
162 TRACE(" - dwHow = %s\n",
163 ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" :
164 ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" :
165 ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown")));
166 }
167 }
168
169 void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) {
170 TRACE(" - enumerating : %s ('%s') - %2d - 0x%08x - %s - 0x%x\n",
171 debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName, ddoi->dwFlags);
172 }
173
174 void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) {
175 TRACE(" - enumerating : %s ('%s'), - %2d - 0x%08x - %s - 0x%x\n",
176 debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName), ddoi->dwFlags);
177 }
178
179 /* This function is a helper to convert a GUID into any possible DInput GUID out there */
180 const char *_dump_dinput_GUID(const GUID *guid) {
181 unsigned int i;
182 static const struct {
183 const GUID *guid;
184 const char *name;
185 } guids[] = {
186 #define FE(x) { &x, #x}
187 FE(GUID_XAxis),
188 FE(GUID_YAxis),
189 FE(GUID_ZAxis),
190 FE(GUID_RxAxis),
191 FE(GUID_RyAxis),
192 FE(GUID_RzAxis),
193 FE(GUID_Slider),
194 FE(GUID_Button),
195 FE(GUID_Key),
196 FE(GUID_POV),
197 FE(GUID_Unknown),
198 FE(GUID_SysMouse),
199 FE(GUID_SysKeyboard),
200 FE(GUID_Joystick),
201 FE(GUID_ConstantForce),
202 FE(GUID_RampForce),
203 FE(GUID_Square),
204 FE(GUID_Sine),
205 FE(GUID_Triangle),
206 FE(GUID_SawtoothUp),
207 FE(GUID_SawtoothDown),
208 FE(GUID_Spring),
209 FE(GUID_Damper),
210 FE(GUID_Inertia),
211 FE(GUID_Friction),
212 FE(GUID_CustomForce)
213 #undef FE
214 };
215 if (guid == NULL)
216 return "null GUID";
217 for (i = 0; i < (sizeof(guids) / sizeof(guids[0])); i++) {
218 if (IsEqualGUID(guids[i].guid, guid)) {
219 return guids[i].name;
220 }
221 }
222 return debugstr_guid(guid);
223 }
224
225 void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) {
226 unsigned int i;
227
228 TRACE("Dumping DIDATAFORMAT structure:\n");
229 TRACE(" - dwSize: %d\n", df->dwSize);
230 if (df->dwSize != sizeof(DIDATAFORMAT)) {
231 WARN("Non-standard DIDATAFORMAT structure size %d\n", df->dwSize);
232 }
233 TRACE(" - dwObjsize: %d\n", df->dwObjSize);
234 if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) {
235 WARN("Non-standard DIOBJECTDATAFORMAT structure size %d\n", df->dwObjSize);
236 }
237 TRACE(" - dwFlags: 0x%08x (", df->dwFlags);
238 switch (df->dwFlags) {
239 case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break;
240 case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break;
241 default: TRACE("unknown"); break;
242 }
243 TRACE(")\n");
244 TRACE(" - dwDataSize: %d\n", df->dwDataSize);
245 TRACE(" - dwNumObjs: %d\n", df->dwNumObjs);
246
247 for (i = 0; i < df->dwNumObjs; i++) {
248 TRACE(" - Object %d:\n", i);
249 TRACE(" * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid));
250 TRACE(" * dwOfs: %d\n", df->rgodf[i].dwOfs);
251 TRACE(" * dwType: 0x%08x\n", df->rgodf[i].dwType);
252 TRACE(" "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n");
253 TRACE(" * dwFlags: 0x%08x\n", df->rgodf[i].dwFlags);
254 TRACE(" "); _dump_ObjectDataFormat_flags(df->rgodf[i].dwFlags); TRACE("\n");
255 }
256 }
257
258 /******************************************************************************
259 * Get the default and the app-specific config keys.
260 */
261 BOOL get_app_key(HKEY *defkey, HKEY *appkey)
262 {
263 char buffer[MAX_PATH+16];
264 DWORD len;
265
266 *appkey = 0;
267
268 /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */
269 if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\DirectInput", defkey))
270 *defkey = 0;
271
272 len = GetModuleFileNameA(0, buffer, MAX_PATH);
273 if (len && len < MAX_PATH)
274 {
275 HKEY tmpkey;
276
277 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */
278 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey))
279 {
280 char *p, *appname = buffer;
281 if ((p = strrchr(appname, '/'))) appname = p + 1;
282 if ((p = strrchr(appname, '\\'))) appname = p + 1;
283 strcat(appname, "\\DirectInput");
284
285 if (RegOpenKeyA(tmpkey, appname, appkey)) *appkey = 0;
286 RegCloseKey(tmpkey);
287 }
288 }
289
290 return *defkey || *appkey;
291 }
292
293 /******************************************************************************
294 * Get a config key from either the app-specific or the default config
295 */
296 DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
297 char *buffer, DWORD size )
298 {
299 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size ))
300 return 0;
301
302 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size ))
303 return 0;
304
305 return ERROR_FILE_NOT_FOUND;
306 }
307
308 /* Conversion between internal data buffer and external data buffer */
309 void fill_DataFormat(void *out, DWORD size, const void *in, const DataFormat *df)
310 {
311 int i;
312 const char *in_c = in;
313 char *out_c = out;
314
315 memset(out, 0, size);
316 if (df->dt == NULL) {
317 /* This means that the app uses Wine's internal data format */
318 memcpy(out, in, min(size, df->internal_format_size));
319 } else {
320 for (i = 0; i < df->size; i++) {
321 if (df->dt[i].offset_in >= 0) {
322 switch (df->dt[i].size) {
323 case 1:
324 TRACE("Copying (c) to %d from %d (value %d)\n",
325 df->dt[i].offset_out, df->dt[i].offset_in, *(in_c + df->dt[i].offset_in));
326 *(out_c + df->dt[i].offset_out) = *(in_c + df->dt[i].offset_in);
327 break;
328
329 case 2:
330 TRACE("Copying (s) to %d from %d (value %d)\n",
331 df->dt[i].offset_out, df->dt[i].offset_in, *((const short *)(in_c + df->dt[i].offset_in)));
332 *((short *)(out_c + df->dt[i].offset_out)) = *((const short *)(in_c + df->dt[i].offset_in));
333 break;
334
335 case 4:
336 TRACE("Copying (i) to %d from %d (value %d)\n",
337 df->dt[i].offset_out, df->dt[i].offset_in, *((const int *)(in_c + df->dt[i].offset_in)));
338 *((int *)(out_c + df->dt[i].offset_out)) = *((const int *)(in_c + df->dt[i].offset_in));
339 break;
340
341 default:
342 memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size);
343 break;
344 }
345 } else {
346 switch (df->dt[i].size) {
347 case 1:
348 TRACE("Copying (c) to %d default value %d\n",
349 df->dt[i].offset_out, df->dt[i].value);
350 *(out_c + df->dt[i].offset_out) = (char) df->dt[i].value;
351 break;
352
353 case 2:
354 TRACE("Copying (s) to %d default value %d\n",
355 df->dt[i].offset_out, df->dt[i].value);
356 *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value;
357 break;
358
359 case 4:
360 TRACE("Copying (i) to %d default value %d\n",
361 df->dt[i].offset_out, df->dt[i].value);
362 *((int *) (out_c + df->dt[i].offset_out)) = df->dt[i].value;
363 break;
364
365 default:
366 memset((out_c + df->dt[i].offset_out), 0, df->dt[i].size);
367 break;
368 }
369 }
370 }
371 }
372 }
373
374 void release_DataFormat(DataFormat * format)
375 {
376 TRACE("Deleting DataFormat: %p\n", format);
377
378 HeapFree(GetProcessHeap(), 0, format->dt);
379 format->dt = NULL;
380 HeapFree(GetProcessHeap(), 0, format->offsets);
381 format->offsets = NULL;
382 HeapFree(GetProcessHeap(), 0, format->user_df);
383 format->user_df = NULL;
384 }
385
386 static inline LPDIOBJECTDATAFORMAT dataformat_to_odf(LPCDIDATAFORMAT df, int idx)
387 {
388 if (idx < 0 || idx >= df->dwNumObjs) return NULL;
389 return (LPDIOBJECTDATAFORMAT)((LPBYTE)df->rgodf + idx * df->dwObjSize);
390 }
391
392 /* dataformat_to_odf_by_type
393 * Find the Nth object of the selected type in the DataFormat
394 */
395 LPDIOBJECTDATAFORMAT dataformat_to_odf_by_type(LPCDIDATAFORMAT df, int n, DWORD type)
396 {
397 int i, nfound = 0;
398
399 for (i=0; i < df->dwNumObjs; i++)
400 {
401 LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(df, i);
402
403 if (odf->dwType & type)
404 {
405 if (n == nfound)
406 return odf;
407
408 nfound++;
409 }
410 }
411
412 return NULL;
413 }
414
415 static HRESULT create_DataFormat(LPCDIDATAFORMAT asked_format, DataFormat *format)
416 {
417 DataTransform *dt;
418 unsigned int i, j;
419 int same = 1;
420 int *done;
421 int index = 0;
422 DWORD next = 0;
423
424 if (!format->wine_df) return DIERR_INVALIDPARAM;
425 done = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, asked_format->dwNumObjs * sizeof(int));
426 dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
427 if (!dt || !done) goto failed;
428
429 if (!(format->offsets = HeapAlloc(GetProcessHeap(), 0, format->wine_df->dwNumObjs * sizeof(int))))
430 goto failed;
431
432 if (!(format->user_df = HeapAlloc(GetProcessHeap(), 0, asked_format->dwSize)))
433 goto failed;
434 memcpy(format->user_df, asked_format, asked_format->dwSize);
435
436 TRACE("Creating DataTransform :\n");
437
438 for (i = 0; i < format->wine_df->dwNumObjs; i++)
439 {
440 format->offsets[i] = -1;
441
442 for (j = 0; j < asked_format->dwNumObjs; j++) {
443 if (done[j] == 1)
444 continue;
445
446 if (/* Check if the application either requests any GUID and if not, it if matches
447 * the GUID of the Wine object.
448 */
449 ((asked_format->rgodf[j].pguid == NULL) ||
450 (format->wine_df->rgodf[i].pguid == NULL) ||
451 (IsEqualGUID(format->wine_df->rgodf[i].pguid, asked_format->rgodf[j].pguid)))
452 &&
453 (/* Then check if it accepts any instance id, and if not, if it matches Wine's
454 * instance id.
455 */
456 ((asked_format->rgodf[j].dwType & DIDFT_INSTANCEMASK) == DIDFT_ANYINSTANCE) ||
457 (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0x00FF) || /* This is mentioned in no DX docs, but it works fine - tested on WinXP */
458 (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(format->wine_df->rgodf[i].dwType)))
459 &&
460 ( /* Then if the asked type matches the one Wine provides */
461 DIDFT_GETTYPE(asked_format->rgodf[j].dwType) & format->wine_df->rgodf[i].dwType))
462 {
463 done[j] = 1;
464
465 TRACE("Matching :\n");
466 TRACE(" - Asked (%d) :\n", j);
467 TRACE(" * GUID: %s ('%s')\n",
468 debugstr_guid(asked_format->rgodf[j].pguid),
469 _dump_dinput_GUID(asked_format->rgodf[j].pguid));
470 TRACE(" * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
471 TRACE(" * dwType: 0x%08x\n", asked_format->rgodf[j].dwType);
472 TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
473 TRACE(" * dwFlags: 0x%08x\n", asked_format->rgodf[j].dwFlags);
474 TRACE(" "); _dump_ObjectDataFormat_flags(asked_format->rgodf[j].dwFlags); TRACE("\n");
475
476 TRACE(" - Wine (%d) :\n", i);
477 TRACE(" * GUID: %s ('%s')\n",
478 debugstr_guid(format->wine_df->rgodf[i].pguid),
479 _dump_dinput_GUID(format->wine_df->rgodf[i].pguid));
480 TRACE(" * Offset: %3d\n", format->wine_df->rgodf[i].dwOfs);
481 TRACE(" * dwType: 0x%08x\n", format->wine_df->rgodf[i].dwType);
482 TRACE(" "); _dump_EnumObjects_flags(format->wine_df->rgodf[i].dwType); TRACE("\n");
483 TRACE(" * dwFlags: 0x%08x\n", format->wine_df->rgodf[i].dwFlags);
484 TRACE(" "); _dump_ObjectDataFormat_flags(format->wine_df->rgodf[i].dwFlags); TRACE("\n");
485
486 if (format->wine_df->rgodf[i].dwType & DIDFT_BUTTON)
487 dt[index].size = sizeof(BYTE);
488 else
489 dt[index].size = sizeof(DWORD);
490 dt[index].offset_in = format->wine_df->rgodf[i].dwOfs;
491 dt[index].offset_out = asked_format->rgodf[j].dwOfs;
492 format->offsets[i] = asked_format->rgodf[j].dwOfs;
493 dt[index].value = 0;
494 next = next + dt[index].size;
495
496 if (format->wine_df->rgodf[i].dwOfs != dt[index].offset_out)
497 same = 0;
498
499 index++;
500 break;
501 }
502 }
503 }
504
505 TRACE("Setting to default value :\n");
506 for (j = 0; j < asked_format->dwNumObjs; j++) {
507 if (done[j] == 0) {
508 TRACE(" - Asked (%d) :\n", j);
509 TRACE(" * GUID: %s ('%s')\n",
510 debugstr_guid(asked_format->rgodf[j].pguid),
511 _dump_dinput_GUID(asked_format->rgodf[j].pguid));
512 TRACE(" * Offset: %3d\n", asked_format->rgodf[j].dwOfs);
513 TRACE(" * dwType: 0x%08x\n", asked_format->rgodf[j].dwType);
514 TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
515 TRACE(" * dwFlags: 0x%08x\n", asked_format->rgodf[j].dwFlags);
516 TRACE(" "); _dump_ObjectDataFormat_flags(asked_format->rgodf[j].dwFlags); TRACE("\n");
517
518 if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
519 dt[index].size = sizeof(BYTE);
520 else
521 dt[index].size = sizeof(DWORD);
522 dt[index].offset_in = -1;
523 dt[index].offset_out = asked_format->rgodf[j].dwOfs;
524 if (asked_format->rgodf[j].dwType & DIDFT_POV)
525 dt[index].value = -1;
526 else
527 dt[index].value = 0;
528 index++;
529
530 same = 0;
531 }
532 }
533
534 format->internal_format_size = format->wine_df->dwDataSize;
535 format->size = index;
536 if (same) {
537 HeapFree(GetProcessHeap(), 0, dt);
538 dt = NULL;
539 }
540 format->dt = dt;
541
542 HeapFree(GetProcessHeap(), 0, done);
543
544 return DI_OK;
545
546 failed:
547 HeapFree(GetProcessHeap(), 0, done);
548 HeapFree(GetProcessHeap(), 0, dt);
549 format->dt = NULL;
550 HeapFree(GetProcessHeap(), 0, format->offsets);
551 format->offsets = NULL;
552 HeapFree(GetProcessHeap(), 0, format->user_df);
553 format->user_df = NULL;
554
555 return DIERR_OUTOFMEMORY;
556 }
557
558 /* find an object by its offset in a data format */
559 static int offset_to_object(const DataFormat *df, int offset)
560 {
561 int i;
562
563 if (!df->offsets) return -1;
564
565 for (i = 0; i < df->wine_df->dwNumObjs; i++)
566 if (df->offsets[i] == offset) return i;
567
568 return -1;
569 }
570
571 int id_to_object(LPCDIDATAFORMAT df, int id)
572 {
573 int i;
574
575 id &= 0x00ffffff;
576 for (i = 0; i < df->dwNumObjs; i++)
577 if ((dataformat_to_odf(df, i)->dwType & 0x00ffffff) == id)
578 return i;
579
580 return -1;
581 }
582
583 static int id_to_offset(const DataFormat *df, int id)
584 {
585 int obj = id_to_object(df->wine_df, id);
586
587 return obj >= 0 && df->offsets ? df->offsets[obj] : -1;
588 }
589
590 int find_property(const DataFormat *df, LPCDIPROPHEADER ph)
591 {
592 switch (ph->dwHow)
593 {
594 case DIPH_BYID: return id_to_object(df->wine_df, ph->dwObj);
595 case DIPH_BYOFFSET: return offset_to_object(df, ph->dwObj);
596 }
597 FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow);
598
599 return -1;
600 }
601
602 static DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD dwSemantic)
603 {
604 DWORD type = (0x0000ff00 & dwSemantic) >> 8;
605 DWORD offset = 0x000000ff & dwSemantic;
606 DWORD obj_instance = 0;
607 BOOL found = FALSE;
608 int i;
609
610 for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
611 {
612 LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
613
614 if (odf->dwOfs == offset)
615 {
616 obj_instance = DIDFT_GETINSTANCE(odf->dwType);
617 found = TRUE;
618 break;
619 }
620 }
621
622 if (!found) return 0;
623
624 if (type & DIDFT_AXIS) type = DIDFT_RELAXIS;
625 if (type & DIDFT_BUTTON) type = DIDFT_PSHBUTTON;
626
627 return type | (0x0000ff00 & (obj_instance << 8));
628 }
629
630 /*
631 * get_mapping_key
632 * Retrieves an open registry key to save the mapping, parametrized for an username,
633 * specific device and specific action mapping guid.
634 */
635 static HKEY get_mapping_key(const WCHAR *device, const WCHAR *username, const WCHAR *guid)
636 {
637 static const WCHAR subkey[] = {
638 'S','o','f','t','w','a','r','e','\\',
639 'W','i','n','e','\\',
640 'D','i','r','e','c','t','I','n','p','u','t','\\',
641 'M','a','p','p','i','n','g','s','\\','%','s','\\','%','s','\\','%','s','\0'};
642 HKEY hkey;
643 WCHAR *keyname;
644
645 keyname = HeapAlloc(GetProcessHeap(), 0,
646 sizeof(WCHAR) * (lstrlenW(subkey) + strlenW(username) + strlenW(device) + strlenW(guid)));
647 sprintfW(keyname, subkey, username, device, guid);
648
649 /* The key used is HKCU\Software\Wine\DirectInput\Mappings\[username]\[device]\[mapping_guid] */
650 if (RegCreateKeyW(HKEY_CURRENT_USER, keyname, &hkey))
651 hkey = 0;
652
653 HeapFree(GetProcessHeap(), 0, keyname);
654
655 return hkey;
656 }
657
658 static HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUsername)
659 {
660 WCHAR *guid_str = NULL;
661 DIDEVICEINSTANCEW didev;
662 HKEY hkey;
663 int i;
664
665 didev.dwSize = sizeof(didev);
666 IDirectInputDevice8_GetDeviceInfo(iface, &didev);
667
668 if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
669 return DI_SETTINGSNOTSAVED;
670
671 hkey = get_mapping_key(didev.tszInstanceName, lpszUsername, guid_str);
672
673 if (!hkey)
674 {
675 CoTaskMemFree(guid_str);
676 return DI_SETTINGSNOTSAVED;
677 }
678
679 /* Write each of the actions mapped for this device.
680 Format is "dwSemantic"="dwObjID" and key is of type REG_DWORD
681 */
682 for (i = 0; i < lpdiaf->dwNumActions; i++)
683 {
684 static const WCHAR format[] = {'%','x','\0'};
685 WCHAR label[9];
686
687 if (IsEqualGUID(&didev.guidInstance, &lpdiaf->rgoAction[i].guidInstance) &&
688 lpdiaf->rgoAction[i].dwHow != DIAH_UNMAPPED)
689 {
690 sprintfW(label, format, lpdiaf->rgoAction[i].dwSemantic);
691 RegSetValueExW(hkey, label, 0, REG_DWORD, (const BYTE*) &lpdiaf->rgoAction[i].dwObjID, sizeof(DWORD));
692 }
693 }
694
695 RegCloseKey(hkey);
696 CoTaskMemFree(guid_str);
697
698 return DI_OK;
699 }
700
701 static BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMATW lpdiaf, const WCHAR *username)
702 {
703 HKEY hkey;
704 WCHAR *guid_str;
705 DIDEVICEINSTANCEW didev;
706 int i, mapped = 0;
707
708 didev.dwSize = sizeof(didev);
709 IDirectInputDevice8_GetDeviceInfo(&This->IDirectInputDevice8W_iface, &didev);
710
711 if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
712 return FALSE;
713
714 hkey = get_mapping_key(didev.tszInstanceName, username, guid_str);
715
716 if (!hkey)
717 {
718 CoTaskMemFree(guid_str);
719 return FALSE;
720 }
721
722 /* Try to read each action in the DIACTIONFORMAT from registry */
723 for (i = 0; i < lpdiaf->dwNumActions; i++)
724 {
725 static const WCHAR format[] = {'%','x','\0'};
726 DWORD id, size = sizeof(DWORD);
727 WCHAR label[9];
728
729 sprintfW(label, format, lpdiaf->rgoAction[i].dwSemantic);
730
731 if (!RegQueryValueExW(hkey, label, 0, NULL, (LPBYTE) &id, &size))
732 {
733 lpdiaf->rgoAction[i].dwObjID = id;
734 lpdiaf->rgoAction[i].guidInstance = didev.guidInstance;
735 lpdiaf->rgoAction[i].dwHow = DIAH_DEFAULT;
736 mapped += 1;
737 }
738 }
739
740 RegCloseKey(hkey);
741 CoTaskMemFree(guid_str);
742
743 return mapped > 0;
744 }
745
746 HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df)
747 {
748 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
749 WCHAR username[MAX_PATH];
750 DWORD username_size = MAX_PATH;
751 int i;
752 BOOL load_success = FALSE, has_actions = FALSE;
753
754 /* Unless asked the contrary by these flags, try to load a previous mapping */
755 if (!(dwFlags & DIDBAM_HWDEFAULTS))
756 {
757 /* Retrieve logged user name if necessary */
758 if (lpszUserName == NULL)
759 GetUserNameW(username, &username_size);
760 else
761 lstrcpynW(username, lpszUserName, MAX_PATH);
762
763 load_success = load_mapping_settings(This, lpdiaf, username);
764 }
765
766 if (load_success) return DI_OK;
767
768 for (i=0; i < lpdiaf->dwNumActions; i++)
769 {
770 /* Don't touch a user configured action */
771 if (lpdiaf->rgoAction[i].dwHow == DIAH_USERCONFIG) continue;
772
773 if ((lpdiaf->rgoAction[i].dwSemantic & devMask) == devMask)
774 {
775 DWORD obj_id = semantic_to_obj_id(This, lpdiaf->rgoAction[i].dwSemantic);
776 DWORD type = DIDFT_GETTYPE(obj_id);
777 DWORD inst = DIDFT_GETINSTANCE(obj_id);
778
779 LPDIOBJECTDATAFORMAT odf;
780
781 if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON;
782 if (type == DIDFT_RELAXIS) type = DIDFT_AXIS;
783
784 /* Make sure the object exists */
785 odf = dataformat_to_odf_by_type(df, inst, type);
786
787 if (odf != NULL)
788 {
789 lpdiaf->rgoAction[i].dwObjID = obj_id;
790 lpdiaf->rgoAction[i].guidInstance = This->guid;
791 lpdiaf->rgoAction[i].dwHow = DIAH_DEFAULT;
792 has_actions = TRUE;
793 }
794 }
795 else if (!(dwFlags & DIDBAM_PRESERVE))
796 {
797 /* We must clear action data belonging to other devices */
798 memset(&lpdiaf->rgoAction[i].guidInstance, 0, sizeof(GUID));
799 lpdiaf->rgoAction[i].dwHow = DIAH_UNMAPPED;
800 }
801 }
802
803 if (!has_actions) return DI_NOEFFECT;
804
805 return IDirectInputDevice8WImpl_BuildActionMap(iface, lpdiaf, lpszUserName, dwFlags);
806 }
807
808 HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, LPCDIDATAFORMAT df)
809 {
810 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
811 DIDATAFORMAT data_format;
812 DIOBJECTDATAFORMAT *obj_df = NULL;
813 DIPROPDWORD dp;
814 DIPROPRANGE dpr;
815 DIPROPSTRING dps;
816 WCHAR username[MAX_PATH];
817 DWORD username_size = MAX_PATH;
818 int i, action = 0, num_actions = 0;
819 unsigned int offset = 0;
820
821 if (This->acquired) return DIERR_ACQUIRED;
822
823 data_format.dwSize = sizeof(data_format);
824 data_format.dwObjSize = sizeof(DIOBJECTDATAFORMAT);
825 data_format.dwFlags = DIDF_RELAXIS;
826 data_format.dwDataSize = lpdiaf->dwDataSize;
827
828 /* Count the actions */
829 for (i=0; i < lpdiaf->dwNumActions; i++)
830 if (IsEqualGUID(&This->guid, &lpdiaf->rgoAction[i].guidInstance))
831 num_actions++;
832
833 if (num_actions == 0) return DI_NOEFFECT;
834
835 This->num_actions = num_actions;
836
837 /* Construct the dataformat and actionmap */
838 obj_df = HeapAlloc(GetProcessHeap(), 0, sizeof(DIOBJECTDATAFORMAT)*num_actions);
839 data_format.rgodf = (LPDIOBJECTDATAFORMAT)obj_df;
840 data_format.dwNumObjs = num_actions;
841
842 HeapFree(GetProcessHeap(), 0, This->action_map);
843 This->action_map = HeapAlloc(GetProcessHeap(), 0, sizeof(ActionMap)*num_actions);
844
845 for (i = 0; i < lpdiaf->dwNumActions; i++)
846 {
847 if (IsEqualGUID(&This->guid, &lpdiaf->rgoAction[i].guidInstance))
848 {
849 DWORD inst = DIDFT_GETINSTANCE(lpdiaf->rgoAction[i].dwObjID);
850 DWORD type = DIDFT_GETTYPE(lpdiaf->rgoAction[i].dwObjID);
851 LPDIOBJECTDATAFORMAT obj;
852
853 if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON;
854 if (type == DIDFT_RELAXIS) type = DIDFT_AXIS;
855
856 obj = dataformat_to_odf_by_type(df, inst, type);
857
858 memcpy(&obj_df[action], obj, df->dwObjSize);
859
860 This->action_map[action].uAppData = lpdiaf->rgoAction[i].uAppData;
861 This->action_map[action].offset = offset;
862 obj_df[action].dwOfs = offset;
863 offset += (type & DIDFT_BUTTON) ? 1 : 4;
864
865 action++;
866 }
867 }
868
869 IDirectInputDevice8_SetDataFormat(iface, &data_format);
870
871 HeapFree(GetProcessHeap(), 0, obj_df);
872
873 /* Set the device properties according to the action format */
874 dpr.diph.dwSize = sizeof(DIPROPRANGE);
875 dpr.lMin = lpdiaf->lAxisMin;
876 dpr.lMax = lpdiaf->lAxisMax;
877 dpr.diph.dwHeaderSize = sizeof(DIPROPHEADER);
878 dpr.diph.dwHow = DIPH_DEVICE;
879 IDirectInputDevice8_SetProperty(iface, DIPROP_RANGE, &dpr.diph);
880
881 if (lpdiaf->dwBufferSize > 0)
882 {
883 dp.diph.dwSize = sizeof(DIPROPDWORD);
884 dp.dwData = lpdiaf->dwBufferSize;
885 dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
886 dp.diph.dwHow = DIPH_DEVICE;
887 IDirectInputDevice8_SetProperty(iface, DIPROP_BUFFERSIZE, &dp.diph);
888 }
889
890 /* Retrieve logged user name if necessary */
891 if (lpszUserName == NULL)
892 GetUserNameW(username, &username_size);
893 else
894 lstrcpynW(username, lpszUserName, MAX_PATH);
895
896 dps.diph.dwSize = sizeof(dps);
897 dps.diph.dwHeaderSize = sizeof(DIPROPHEADER);
898 dps.diph.dwObj = 0;
899 dps.diph.dwHow = DIPH_DEVICE;
900 if (dwFlags & DIDSAM_NOUSER)
901 dps.wsz[0] = '\0';
902 else
903 lstrcpynW(dps.wsz, username, sizeof(dps.wsz)/sizeof(WCHAR));
904 IDirectInputDevice8_SetProperty(iface, DIPROP_USERNAME, &dps.diph);
905
906 /* Save the settings to disk */
907 save_mapping_settings(iface, lpdiaf, username);
908
909 return DI_OK;
910 }
911
912 /******************************************************************************
913 * queue_event - add new event to the ring queue
914 */
915
916 void queue_event(LPDIRECTINPUTDEVICE8A iface, int inst_id, DWORD data, DWORD time, DWORD seq)
917 {
918 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
919 int next_pos, ofs = id_to_offset(&This->data_format, inst_id);
920
921 /* Event is being set regardless of the queue state */
922 if (This->hEvent) SetEvent(This->hEvent);
923
924 if (!This->queue_len || This->overflow || ofs < 0) return;
925
926 next_pos = (This->queue_head + 1) % This->queue_len;
927 if (next_pos == This->queue_tail)
928 {
929 TRACE(" queue overflowed\n");
930 This->overflow = TRUE;
931 return;
932 }
933
934 TRACE(" queueing %d at offset %d (queue head %d / size %d)\n",
935 data, ofs, This->queue_head, This->queue_len);
936
937 This->data_queue[This->queue_head].dwOfs = ofs;
938 This->data_queue[This->queue_head].dwData = data;
939 This->data_queue[This->queue_head].dwTimeStamp = time;
940 This->data_queue[This->queue_head].dwSequence = seq;
941
942 /* Set uAppData by means of action mapping */
943 if (This->num_actions > 0)
944 {
945 int i;
946 for (i=0; i < This->num_actions; i++)
947 {
948 if (This->action_map[i].offset == ofs)
949 {
950 TRACE("Offset %d mapped to uAppData %lu\n", ofs, This->action_map[i].uAppData);
951 This->data_queue[This->queue_head].uAppData = This->action_map[i].uAppData;
952 break;
953 }
954 }
955 }
956
957 This->queue_head = next_pos;
958 /* Send event if asked */
959 }
960
961 /******************************************************************************
962 * Acquire
963 */
964
965 HRESULT WINAPI IDirectInputDevice2WImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
966 {
967 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
968 HRESULT res;
969
970 TRACE("(%p)\n", This);
971
972 if (!This->data_format.user_df) return DIERR_INVALIDPARAM;
973 if (This->dwCoopLevel & DISCL_FOREGROUND && This->win != GetForegroundWindow())
974 return DIERR_OTHERAPPHASPRIO;
975
976 EnterCriticalSection(&This->crit);
977 res = This->acquired ? S_FALSE : DI_OK;
978 This->acquired = 1;
979 if (res == DI_OK)
980 check_dinput_hooks(iface);
981 LeaveCriticalSection(&This->crit);
982
983 return res;
984 }
985
986 HRESULT WINAPI IDirectInputDevice2AImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
987 {
988 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
989 return IDirectInputDevice2WImpl_Acquire(IDirectInputDevice8W_from_impl(This));
990 }
991
992
993 /******************************************************************************
994 * Unacquire
995 */
996
997 HRESULT WINAPI IDirectInputDevice2WImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
998 {
999 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1000 HRESULT res;
1001
1002 TRACE("(%p)\n", This);
1003
1004 EnterCriticalSection(&This->crit);
1005 res = !This->acquired ? DI_NOEFFECT : DI_OK;
1006 This->acquired = 0;
1007 if (res == DI_OK)
1008 check_dinput_hooks(iface);
1009 LeaveCriticalSection(&This->crit);
1010
1011 return res;
1012 }
1013
1014 HRESULT WINAPI IDirectInputDevice2AImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
1015 {
1016 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1017 return IDirectInputDevice2WImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
1018 }
1019
1020 /******************************************************************************
1021 * IDirectInputDeviceA
1022 */
1023
1024 HRESULT WINAPI IDirectInputDevice2WImpl_SetDataFormat(LPDIRECTINPUTDEVICE8W iface, LPCDIDATAFORMAT df)
1025 {
1026 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1027 HRESULT res = DI_OK;
1028
1029 if (!df) return E_POINTER;
1030 TRACE("(%p) %p\n", This, df);
1031 _dump_DIDATAFORMAT(df);
1032
1033 if (df->dwSize != sizeof(DIDATAFORMAT)) return DIERR_INVALIDPARAM;
1034 if (This->acquired) return DIERR_ACQUIRED;
1035
1036 EnterCriticalSection(&This->crit);
1037
1038 release_DataFormat(&This->data_format);
1039 res = create_DataFormat(df, &This->data_format);
1040
1041 LeaveCriticalSection(&This->crit);
1042 return res;
1043 }
1044
1045 HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(LPDIRECTINPUTDEVICE8A iface, LPCDIDATAFORMAT df)
1046 {
1047 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1048 return IDirectInputDevice2WImpl_SetDataFormat(IDirectInputDevice8W_from_impl(This), df);
1049 }
1050
1051 /******************************************************************************
1052 * SetCooperativeLevel
1053 *
1054 * Set cooperative level and the source window for the events.
1055 */
1056 HRESULT WINAPI IDirectInputDevice2WImpl_SetCooperativeLevel(LPDIRECTINPUTDEVICE8W iface, HWND hwnd, DWORD dwflags)
1057 {
1058 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1059
1060 TRACE("(%p) %p,0x%08x\n", This, hwnd, dwflags);
1061 _dump_cooperativelevel_DI(dwflags);
1062
1063 if ((dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == 0 ||
1064 (dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE) ||
1065 (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == 0 ||
1066 (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == (DISCL_FOREGROUND | DISCL_BACKGROUND))
1067 return DIERR_INVALIDPARAM;
1068
1069 if (hwnd && GetWindowLongW(hwnd, GWL_STYLE) & WS_CHILD) return E_HANDLE;
1070
1071 if (!hwnd && dwflags == (DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))
1072 hwnd = GetDesktopWindow();
1073
1074 if (!IsWindow(hwnd)) return E_HANDLE;
1075
1076 /* For security reasons native does not allow exclusive background level
1077 for mouse and keyboard only */
1078 if (dwflags & DISCL_EXCLUSIVE && dwflags & DISCL_BACKGROUND &&
1079 (IsEqualGUID(&This->guid, &GUID_SysMouse) ||
1080 IsEqualGUID(&This->guid, &GUID_SysKeyboard)))
1081 return DIERR_UNSUPPORTED;
1082
1083 /* Store the window which asks for the mouse */
1084 EnterCriticalSection(&This->crit);
1085 This->win = hwnd;
1086 This->dwCoopLevel = dwflags;
1087 LeaveCriticalSection(&This->crit);
1088
1089 return DI_OK;
1090 }
1091
1092 HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(LPDIRECTINPUTDEVICE8A iface, HWND hwnd, DWORD dwflags)
1093 {
1094 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1095 return IDirectInputDevice2WImpl_SetCooperativeLevel(IDirectInputDevice8W_from_impl(This), hwnd, dwflags);
1096 }
1097
1098 /******************************************************************************
1099 * SetEventNotification : specifies event to be sent on state change
1100 */
1101 HRESULT WINAPI IDirectInputDevice2WImpl_SetEventNotification(LPDIRECTINPUTDEVICE8W iface, HANDLE event)
1102 {
1103 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1104
1105 TRACE("(%p) %p\n", This, event);
1106
1107 EnterCriticalSection(&This->crit);
1108 This->hEvent = event;
1109 LeaveCriticalSection(&This->crit);
1110 return DI_OK;
1111 }
1112
1113 HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, HANDLE event)
1114 {
1115 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1116 return IDirectInputDevice2WImpl_SetEventNotification(IDirectInputDevice8W_from_impl(This), event);
1117 }
1118
1119
1120 ULONG WINAPI IDirectInputDevice2WImpl_Release(LPDIRECTINPUTDEVICE8W iface)
1121 {
1122 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1123 ULONG ref = InterlockedDecrement(&(This->ref));
1124
1125 TRACE("(%p) releasing from %d\n", This, ref + 1);
1126
1127 if (ref) return ref;
1128
1129 IDirectInputDevice_Unacquire(iface);
1130 /* Reset the FF state, free all effects, etc */
1131 IDirectInputDevice8_SendForceFeedbackCommand(iface, DISFFC_RESET);
1132
1133 HeapFree(GetProcessHeap(), 0, This->data_queue);
1134
1135 /* Free data format */
1136 HeapFree(GetProcessHeap(), 0, This->data_format.wine_df->rgodf);
1137 HeapFree(GetProcessHeap(), 0, This->data_format.wine_df);
1138 release_DataFormat(&This->data_format);
1139
1140 /* Free action mapping */
1141 HeapFree(GetProcessHeap(), 0, This->action_map);
1142
1143 EnterCriticalSection( &This->dinput->crit );
1144 list_remove( &This->entry );
1145 LeaveCriticalSection( &This->dinput->crit );
1146
1147 IDirectInput_Release(&This->dinput->IDirectInput7A_iface);
1148 This->crit.DebugInfo->Spare[0] = 0;
1149 DeleteCriticalSection(&This->crit);
1150
1151 HeapFree(GetProcessHeap(), 0, This);
1152
1153 return DI_OK;
1154 }
1155
1156 ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface)
1157 {
1158 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1159 return IDirectInputDevice2WImpl_Release(IDirectInputDevice8W_from_impl(This));
1160 }
1161
1162 HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W iface, REFIID riid, LPVOID *ppobj)
1163 {
1164 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1165
1166 TRACE("(%p this=%p,%s,%p)\n", iface, This, debugstr_guid(riid), ppobj);
1167 if (IsEqualGUID(&IID_IUnknown, riid) ||
1168 IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
1169 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
1170 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
1171 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
1172 {
1173 IDirectInputDevice2_AddRef(iface);
1174 *ppobj = IDirectInputDevice8A_from_impl(This);
1175 return DI_OK;
1176 }
1177 if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
1178 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
1179 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
1180 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
1181 {
1182 IDirectInputDevice2_AddRef(iface);
1183 *ppobj = IDirectInputDevice8W_from_impl(This);
1184 return DI_OK;
1185 }
1186
1187 WARN("Unsupported interface!\n");
1188 return E_FAIL;
1189 }
1190
1191 HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(LPDIRECTINPUTDEVICE8A iface, REFIID riid, LPVOID *ppobj)
1192 {
1193 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1194 return IDirectInputDevice2WImpl_QueryInterface(IDirectInputDevice8W_from_impl(This), riid, ppobj);
1195 }
1196
1197 ULONG WINAPI IDirectInputDevice2WImpl_AddRef(LPDIRECTINPUTDEVICE8W iface)
1198 {
1199 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1200 return InterlockedIncrement(&This->ref);
1201 }
1202
1203 ULONG WINAPI IDirectInputDevice2AImpl_AddRef(LPDIRECTINPUTDEVICE8A iface)
1204 {
1205 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1206 return IDirectInputDevice2WImpl_AddRef(IDirectInputDevice8W_from_impl(This));
1207 }
1208
1209 HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(LPDIRECTINPUTDEVICE8A iface,
1210 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID lpvRef, DWORD dwFlags)
1211 {
1212 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1213 DIDEVICEOBJECTINSTANCEA ddoi;
1214 int i;
1215
1216 TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
1217 TRACE(" - flags = ");
1218 _dump_EnumObjects_flags(dwFlags);
1219 TRACE("\n");
1220
1221 /* Only the fields till dwFFMaxForce are relevant */
1222 memset(&ddoi, 0, sizeof(ddoi));
1223 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
1224
1225 for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
1226 {
1227 LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
1228
1229 if (dwFlags != DIDFT_ALL && !(dwFlags & DIDFT_GETTYPE(odf->dwType))) continue;
1230 if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK)
1231 continue;
1232
1233 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break;
1234 }
1235
1236 return DI_OK;
1237 }
1238
1239 HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
1240 LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef, DWORD dwFlags)
1241 {
1242 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1243 DIDEVICEOBJECTINSTANCEW ddoi;
1244 int i;
1245
1246 TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
1247 TRACE(" - flags = ");
1248 _dump_EnumObjects_flags(dwFlags);
1249 TRACE("\n");
1250
1251 /* Only the fields till dwFFMaxForce are relevant */
1252 memset(&ddoi, 0, sizeof(ddoi));
1253 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, dwFFMaxForce);
1254
1255 for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++)
1256 {
1257 LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i);
1258
1259 if (dwFlags != DIDFT_ALL && !(dwFlags & DIDFT_GETTYPE(odf->dwType))) continue;
1260 if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK)
1261 continue;
1262
1263 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break;
1264 }
1265
1266 return DI_OK;
1267 }
1268
1269 /******************************************************************************
1270 * GetProperty
1271 */
1272
1273 HRESULT WINAPI IDirectInputDevice2WImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
1274 {
1275 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1276
1277 TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
1278 _dump_DIPROPHEADER(pdiph);
1279
1280 if (!IS_DIPROP(rguid)) return DI_OK;
1281
1282 switch (LOWORD(rguid))
1283 {
1284 case (DWORD_PTR) DIPROP_BUFFERSIZE:
1285 {
1286 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
1287
1288 if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
1289
1290 pd->dwData = This->queue_len;
1291 TRACE("buffersize = %d\n", pd->dwData);
1292 break;
1293 }
1294 case (DWORD_PTR) DIPROP_USERNAME:
1295 {
1296 LPDIPROPSTRING ps = (LPDIPROPSTRING)pdiph;
1297 struct DevicePlayer *device_player;
1298
1299 if (pdiph->dwSize != sizeof(DIPROPSTRING)) return DIERR_INVALIDPARAM;
1300
1301 LIST_FOR_EACH_ENTRY(device_player, &This->dinput->device_players,
1302 struct DevicePlayer, entry)
1303 {
1304 if (IsEqualGUID(&device_player->instance_guid, &This->guid))
1305 {
1306 if (*device_player->username)
1307 {
1308 lstrcpynW(ps->wsz, device_player->username, sizeof(ps->wsz)/sizeof(WCHAR));
1309 return DI_OK;
1310 }
1311 else break;
1312 }
1313 }
1314 return S_FALSE;
1315 }
1316 case (DWORD_PTR) DIPROP_VIDPID:
1317 FIXME("DIPROP_VIDPID not implemented\n");
1318 return DIERR_UNSUPPORTED;
1319 default:
1320 FIXME("Unknown property %s\n", debugstr_guid(rguid));
1321 return DIERR_INVALIDPARAM;
1322 }
1323
1324 return DI_OK;
1325 }
1326
1327 HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
1328 {
1329 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1330 return IDirectInputDevice2WImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
1331 }
1332
1333 /******************************************************************************
1334 * SetProperty
1335 */
1336
1337 HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty(
1338 LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIPROPHEADER pdiph)
1339 {
1340 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1341
1342 TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
1343 _dump_DIPROPHEADER(pdiph);
1344
1345 if (!IS_DIPROP(rguid)) return DI_OK;
1346
1347 switch (LOWORD(rguid))
1348 {
1349 case (DWORD_PTR) DIPROP_AXISMODE:
1350 {
1351 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
1352
1353 if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
1354 if (pdiph->dwHow == DIPH_DEVICE && pdiph->dwObj) return DIERR_INVALIDPARAM;
1355 if (This->acquired) return DIERR_ACQUIRED;
1356 if (pdiph->dwHow != DIPH_DEVICE) return DIERR_UNSUPPORTED;
1357 if (!This->data_format.user_df) return DI_OK;
1358
1359 TRACE("Axis mode: %s\n", pd->dwData == DIPROPAXISMODE_ABS ? "absolute" :
1360 "relative");
1361
1362 EnterCriticalSection(&This->crit);
1363 This->data_format.user_df->dwFlags &= ~DIDFT_AXIS;
1364 This->data_format.user_df->dwFlags |= pd->dwData == DIPROPAXISMODE_ABS ?
1365 DIDF_ABSAXIS : DIDF_RELAXIS;
1366 LeaveCriticalSection(&This->crit);
1367 break;
1368 }
1369 case (DWORD_PTR) DIPROP_BUFFERSIZE:
1370 {
1371 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph;
1372
1373 if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM;
1374 if (This->acquired) return DIERR_ACQUIRED;
1375
1376 TRACE("buffersize = %d\n", pd->dwData);
1377
1378 EnterCriticalSection(&This->crit);
1379 HeapFree(GetProcessHeap(), 0, This->data_queue);
1380
1381 This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0,
1382 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1383 This->queue_head = This->queue_tail = This->overflow = 0;
1384 This->queue_len = pd->dwData;
1385
1386 LeaveCriticalSection(&This->crit);
1387 break;
1388 }
1389 case (DWORD_PTR) DIPROP_USERNAME:
1390 {
1391 LPCDIPROPSTRING ps = (LPCDIPROPSTRING)pdiph;
1392 struct DevicePlayer *device_player;
1393 BOOL found = FALSE;
1394
1395 if (pdiph->dwSize != sizeof(DIPROPSTRING)) return DIERR_INVALIDPARAM;
1396
1397 LIST_FOR_EACH_ENTRY(device_player, &This->dinput->device_players,
1398 struct DevicePlayer, entry)
1399 {
1400 if (IsEqualGUID(&device_player->instance_guid, &This->guid))
1401 {
1402 found = TRUE;
1403 break;
1404 }
1405 }
1406 if (!found && (device_player =
1407 HeapAlloc(GetProcessHeap(), 0, sizeof(struct DevicePlayer))))
1408 {
1409 list_add_tail(&This->dinput->device_players, &device_player->entry);
1410 device_player->instance_guid = This->guid;
1411 }
1412 if (device_player)
1413 lstrcpynW(device_player->username, ps->wsz,
1414 sizeof(device_player->username)/sizeof(WCHAR));
1415 break;
1416 }
1417 default:
1418 WARN("Unknown property %s\n", debugstr_guid(rguid));
1419 return DIERR_UNSUPPORTED;
1420 }
1421
1422 return DI_OK;
1423 }
1424
1425 HRESULT WINAPI IDirectInputDevice2AImpl_SetProperty(
1426 LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER pdiph)
1427 {
1428 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1429 return IDirectInputDevice2WImpl_SetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
1430 }
1431
1432 HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
1433 LPDIRECTINPUTDEVICE8A iface,
1434 LPDIDEVICEOBJECTINSTANCEA pdidoi,
1435 DWORD dwObj,
1436 DWORD dwHow)
1437 {
1438 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1439 DIDEVICEOBJECTINSTANCEW didoiW;
1440 HRESULT res;
1441
1442 if (!pdidoi ||
1443 (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA) &&
1444 pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A)))
1445 return DIERR_INVALIDPARAM;
1446
1447 didoiW.dwSize = sizeof(didoiW);
1448 res = IDirectInputDevice2WImpl_GetObjectInfo(IDirectInputDevice8W_from_impl(This), &didoiW, dwObj, dwHow);
1449 if (res == DI_OK)
1450 {
1451 DWORD dwSize = pdidoi->dwSize;
1452
1453 memset(pdidoi, 0, pdidoi->dwSize);
1454 pdidoi->dwSize = dwSize;
1455 pdidoi->guidType = didoiW.guidType;
1456 pdidoi->dwOfs = didoiW.dwOfs;
1457 pdidoi->dwType = didoiW.dwType;
1458 pdidoi->dwFlags = didoiW.dwFlags;
1459 }
1460
1461 return res;
1462 }
1463
1464 HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(
1465 LPDIRECTINPUTDEVICE8W iface,
1466 LPDIDEVICEOBJECTINSTANCEW pdidoi,
1467 DWORD dwObj,
1468 DWORD dwHow)
1469 {
1470 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1471 DWORD dwSize;
1472 LPDIOBJECTDATAFORMAT odf;
1473 int idx = -1;
1474
1475 TRACE("(%p) %d(0x%08x) -> %p\n", This, dwHow, dwObj, pdidoi);
1476
1477 if (!pdidoi ||
1478 (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW) &&
1479 pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W)))
1480 return DIERR_INVALIDPARAM;
1481
1482 switch (dwHow)
1483 {
1484 case DIPH_BYOFFSET:
1485 if (!This->data_format.offsets) break;
1486 for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--)
1487 if (This->data_format.offsets[idx] == dwObj) break;
1488 break;
1489 case DIPH_BYID:
1490 dwObj &= 0x00ffffff;
1491 for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--)
1492 if ((dataformat_to_odf(This->data_format.wine_df, idx)->dwType & 0x00ffffff) == dwObj)
1493 break;
1494 break;
1495
1496 case DIPH_BYUSAGE:
1497 FIXME("dwHow = DIPH_BYUSAGE not implemented\n");
1498 break;
1499 default:
1500 WARN("invalid parameter: dwHow = %08x\n", dwHow);
1501 return DIERR_INVALIDPARAM;
1502 }
1503 if (idx < 0) return DIERR_OBJECTNOTFOUND;
1504
1505 odf = dataformat_to_odf(This->data_format.wine_df, idx);
1506 dwSize = pdidoi->dwSize; /* save due to memset below */
1507 memset(pdidoi, 0, pdidoi->dwSize);
1508 pdidoi->dwSize = dwSize;
1509 if (odf->pguid) pdidoi->guidType = *odf->pguid;
1510 pdidoi->dwOfs = This->data_format.offsets ? This->data_format.offsets[idx] : odf->dwOfs;
1511 pdidoi->dwType = odf->dwType;
1512 pdidoi->dwFlags = odf->dwFlags;
1513
1514 return DI_OK;
1515 }
1516
1517 HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceData(LPDIRECTINPUTDEVICE8W iface, DWORD dodsize,
1518 LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
1519 {
1520 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1521 HRESULT ret = DI_OK;
1522 int len;
1523
1524 TRACE("(%p) %p -> %p(%d) x%d, 0x%08x\n",
1525 This, dod, entries, entries ? *entries : 0, dodsize, flags);
1526
1527 if (This->dinput->dwVersion == 0x0800 || dodsize == sizeof(DIDEVICEOBJECTDATA_DX3))
1528 {
1529 if (!This->queue_len) return DIERR_NOTBUFFERED;
1530 if (!This->acquired) return DIERR_NOTACQUIRED;
1531 }
1532
1533 if (!This->queue_len)
1534 return DI_OK;
1535 if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3))
1536 return DIERR_INVALIDPARAM;
1537
1538 IDirectInputDevice2_Poll(iface);
1539 EnterCriticalSection(&This->crit);
1540
1541 len = This->queue_head - This->queue_tail;
1542 if (len < 0) len += This->queue_len;
1543
1544 if ((*entries != INFINITE) && (len > *entries)) len = *entries;
1545
1546 if (dod)
1547 {
1548 int i;
1549 for (i = 0; i < len; i++)
1550 {
1551 int n = (This->queue_tail + i) % This->queue_len;
1552 memcpy((char *)dod + dodsize * i, This->data_queue + n, dodsize);
1553 }
1554 }
1555 *entries = len;
1556
1557 if (This->overflow && This->dinput->dwVersion == 0x0800)
1558 ret = DI_BUFFEROVERFLOW;
1559
1560 if (!(flags & DIGDD_PEEK))
1561 {
1562 /* Advance reading position */
1563 This->queue_tail = (This->queue_tail + len) % This->queue_len;
1564 This->overflow = FALSE;
1565 }
1566
1567 LeaveCriticalSection(&This->crit);
1568
1569 TRACE("Returning %d events queued\n", *entries);
1570 return ret;
1571 }
1572
1573 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, DWORD dodsize,
1574 LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
1575 {
1576 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1577 return IDirectInputDevice2WImpl_GetDeviceData(IDirectInputDevice8W_from_impl(This), dodsize, dod, entries, flags);
1578 }
1579
1580 HRESULT WINAPI IDirectInputDevice2WImpl_RunControlPanel(LPDIRECTINPUTDEVICE8W iface, HWND hwndOwner, DWORD dwFlags)
1581 {
1582 FIXME("(this=%p,%p,0x%08x): stub!\n", iface, hwndOwner, dwFlags);
1583
1584 return DI_OK;
1585 }
1586
1587 HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(LPDIRECTINPUTDEVICE8A iface, HWND hwndOwner, DWORD dwFlags)
1588 {
1589 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1590 return IDirectInputDevice2WImpl_RunControlPanel(IDirectInputDevice8W_from_impl(This), hwndOwner, dwFlags);
1591 }
1592
1593 HRESULT WINAPI IDirectInputDevice2WImpl_Initialize(LPDIRECTINPUTDEVICE8W iface, HINSTANCE hinst, DWORD dwVersion,
1594 REFGUID rguid)
1595 {
1596 FIXME("(this=%p,%p,%d,%s): stub!\n", iface, hinst, dwVersion, debugstr_guid(rguid));
1597 return DI_OK;
1598 }
1599
1600 HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(LPDIRECTINPUTDEVICE8A iface, HINSTANCE hinst, DWORD dwVersion,
1601 REFGUID rguid)
1602 {
1603 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1604 return IDirectInputDevice2WImpl_Initialize(IDirectInputDevice8W_from_impl(This), hinst, dwVersion, rguid);
1605 }
1606
1607 /******************************************************************************
1608 * IDirectInputDevice2A
1609 */
1610
1611 HRESULT WINAPI IDirectInputDevice2WImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIEFFECT lpeff,
1612 LPDIRECTINPUTEFFECT *ppdef, LPUNKNOWN pUnkOuter)
1613 {
1614 FIXME("(this=%p,%s,%p,%p,%p): stub!\n", iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
1615
1616 FIXME("not available in the generic implementation\n");
1617 *ppdef = NULL;
1618 return DIERR_UNSUPPORTED;
1619 }
1620
1621 HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIEFFECT lpeff,
1622 LPDIRECTINPUTEFFECT *ppdef, LPUNKNOWN pUnkOuter)
1623 {
1624 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1625 return IDirectInputDevice2WImpl_CreateEffect(IDirectInputDevice8W_from_impl(This), rguid, lpeff, ppdef, pUnkOuter);
1626 }
1627
1628 HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
1629 LPDIRECTINPUTDEVICE8A iface,
1630 LPDIENUMEFFECTSCALLBACKA lpCallback,
1631 LPVOID lpvRef,
1632 DWORD dwFlags)
1633 {
1634 FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1635 iface, lpCallback, lpvRef, dwFlags);
1636
1637 return DI_OK;
1638 }
1639
1640 HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects(
1641 LPDIRECTINPUTDEVICE8W iface,
1642 LPDIENUMEFFECTSCALLBACKW lpCallback,
1643 LPVOID lpvRef,
1644 DWORD dwFlags)
1645 {
1646 FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
1647 iface, lpCallback, lpvRef, dwFlags);
1648
1649 return DI_OK;
1650 }
1651
1652 HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
1653 LPDIRECTINPUTDEVICE8A iface,
1654 LPDIEFFECTINFOA lpdei,
1655 REFGUID rguid)
1656 {
1657 FIXME("(this=%p,%p,%s): stub!\n",
1658 iface, lpdei, debugstr_guid(rguid));
1659 return DI_OK;
1660 }
1661
1662 HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo(
1663 LPDIRECTINPUTDEVICE8W iface,
1664 LPDIEFFECTINFOW lpdei,
1665 REFGUID rguid)
1666 {
1667 FIXME("(this=%p,%p,%s): stub!\n",
1668 iface, lpdei, debugstr_guid(rguid));
1669 return DI_OK;
1670 }
1671
1672 HRESULT WINAPI IDirectInputDevice2WImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8W iface, LPDWORD pdwOut)
1673 {
1674 FIXME("(this=%p,%p): stub!\n", iface, pdwOut);
1675 return DI_OK;
1676 }
1677
1678 HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8A iface, LPDWORD pdwOut)
1679 {
1680 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1681 return IDirectInputDevice2WImpl_GetForceFeedbackState(IDirectInputDevice8W_from_impl(This), pdwOut);
1682 }
1683
1684 HRESULT WINAPI IDirectInputDevice2WImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags)
1685 {
1686 TRACE("(%p) 0x%08x:\n", iface, dwFlags);
1687 return DI_NOEFFECT;
1688 }
1689
1690 HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags)
1691 {
1692 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1693 return IDirectInputDevice2WImpl_SendForceFeedbackCommand(IDirectInputDevice8W_from_impl(This), dwFlags);
1694 }
1695
1696 HRESULT WINAPI IDirectInputDevice2WImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface,
1697 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID lpvRef, DWORD dwFlags)
1698 {
1699 FIXME("(this=%p,%p,%p,0x%08x): stub!\n", iface, lpCallback, lpvRef, dwFlags);
1700 return DI_OK;
1701 }
1702
1703 HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8A iface,
1704 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID lpvRef, DWORD dwFlags)
1705 {
1706 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1707 return IDirectInputDevice2WImpl_EnumCreatedEffectObjects(IDirectInputDevice8W_from_impl(This), lpCallback, lpvRef, dwFlags);
1708 }
1709
1710 HRESULT WINAPI IDirectInputDevice2WImpl_Escape(LPDIRECTINPUTDEVICE8W iface, LPDIEFFESCAPE lpDIEEsc)
1711 {
1712 FIXME("(this=%p,%p): stub!\n", iface, lpDIEEsc);
1713 return DI_OK;
1714 }
1715
1716 HRESULT WINAPI IDirectInputDevice2AImpl_Escape(LPDIRECTINPUTDEVICE8A iface, LPDIEFFESCAPE lpDIEEsc)
1717 {
1718 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1719 return IDirectInputDevice2WImpl_Escape(IDirectInputDevice8W_from_impl(This), lpDIEEsc);
1720 }
1721
1722 HRESULT WINAPI IDirectInputDevice2WImpl_Poll(LPDIRECTINPUTDEVICE8W iface)
1723 {
1724 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
1725
1726 if (!This->acquired) return DIERR_NOTACQUIRED;
1727
1728 check_dinput_events();
1729 return DI_OK;
1730 }
1731
1732 HRESULT WINAPI IDirectInputDevice2AImpl_Poll(LPDIRECTINPUTDEVICE8A iface)
1733 {
1734 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1735 return IDirectInputDevice2WImpl_Poll(IDirectInputDevice8W_from_impl(This));
1736 }
1737
1738 HRESULT WINAPI IDirectInputDevice2WImpl_SendDeviceData(LPDIRECTINPUTDEVICE8W iface, DWORD cbObjectData,
1739 LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut,
1740 DWORD dwFlags)
1741 {
1742 FIXME("(this=%p,0x%08x,%p,%p,0x%08x): stub!\n", iface, cbObjectData, rgdod, pdwInOut, dwFlags);
1743
1744 return DI_OK;
1745 }
1746
1747 HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(LPDIRECTINPUTDEVICE8A iface, DWORD cbObjectData,
1748 LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut,
1749 DWORD dwFlags)
1750 {
1751 IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
1752 return IDirectInputDevice2WImpl_SendDeviceData(IDirectInputDevice8W_from_impl(This), cbObjectData, rgdod,
1753 pdwInOut, dwFlags);
1754 }
1755
1756 HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface,
1757 LPCSTR lpszFileName,
1758 LPDIENUMEFFECTSINFILECALLBACK pec,
1759 LPVOID pvRef,
1760 DWORD dwFlags)
1761 {
1762 FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
1763
1764 return DI_OK;
1765 }
1766
1767 HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface,
1768 LPCWSTR lpszFileName,
1769 LPDIENUMEFFECTSINFILECALLBACK pec,
1770 LPVOID pvRef,
1771 DWORD dwFlags)
1772 {
1773 FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags);
1774
1775 return DI_OK;
1776 }
1777
1778 HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface,
1779 LPCSTR lpszFileName,
1780 DWORD dwEntries,
1781 LPDIFILEEFFECT rgDiFileEft,
1782 DWORD dwFlags)
1783 {
1784 FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
1785
1786 return DI_OK;
1787 }
1788
1789 HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface,
1790 LPCWSTR lpszFileName,
1791 DWORD dwEntries,
1792 LPDIFILEEFFECT rgDiFileEft,
1793 DWORD dwFlags)
1794 {
1795 FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
1796
1797 return DI_OK;
1798 }
1799
1800 HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
1801 LPDIACTIONFORMATW lpdiaf,
1802 LPCWSTR lpszUserName,
1803 DWORD dwFlags)
1804 {
1805 FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
1806 #define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n");
1807 X(DIDBAM_DEFAULT)
1808 X(DIDBAM_PRESERVE)
1809 X(DIDBAM_INITIALIZE)
1810 X(DIDBAM_HWDEFAULTS)
1811 #undef X
1812
1813 return DI_OK;
1814 }
1815
1816 HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface,
1817 LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader)
1818 {
1819 FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
1820
1821 return DI_OK;
1822 }
1823
1824 HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface,
1825 LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
1826 {
1827 FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
1828
1829 return DI_OK;
1830 }