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