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