1 /* DirectInput 2 * 3 * Copyright 1998 Marcus Meissner 4 * Copyright 1998,1999 Lionel Ulmer 5 * Copyright 2000-2002 TransGaming Technologies Inc. 6 * Copyright 2007 Vitaliy Margolen 7 * 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 /* Status: 24 * 25 * - Tomb Raider 2 Demo: 26 * Playable using keyboard only. 27 * - WingCommander Prophecy Demo: 28 * Doesn't get Input Focus. 29 * 30 * - Fallout : works great in X and DGA mode 31 */ 32 33 #include <assert.h> 34 #include <stdarg.h> 35 #include <string.h> 36 37 #define COBJMACROS 38 #define NONAMELESSUNION 39 40 #include "wine/debug.h" 41 #include "wine/heap.h" 42 #include "wine/unicode.h" 43 #include "wine/asm.h" 44 #include "windef.h" 45 #include "winbase.h" 46 #include "winuser.h" 47 #include "winerror.h" 48 #include "objbase.h" 49 #include "rpcproxy.h" 50 #include "initguid.h" 51 #include "devguid.h" 52 #include "dinput_private.h" 53 #include "device_private.h" 54 #include "dinputd.h" 55 56 WINE_DEFAULT_DEBUG_CHANNEL(dinput); 57 58 static const IDirectInput7AVtbl ddi7avt; 59 static const IDirectInput7WVtbl ddi7wvt; 60 static const IDirectInput8AVtbl ddi8avt; 61 static const IDirectInput8WVtbl ddi8wvt; 62 static const IDirectInputJoyConfig8Vtbl JoyConfig8vt; 63 64 static inline IDirectInputImpl *impl_from_IDirectInput7A( IDirectInput7A *iface ) 65 { 66 return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7A_iface ); 67 } 68 69 static inline IDirectInputImpl *impl_from_IDirectInput7W( IDirectInput7W *iface ) 70 { 71 return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput7W_iface ); 72 } 73 74 static inline IDirectInputImpl *impl_from_IDirectInput8A( IDirectInput8A *iface ) 75 { 76 return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8A_iface ); 77 } 78 79 static inline IDirectInputImpl *impl_from_IDirectInput8W( IDirectInput8W *iface ) 80 { 81 return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInput8W_iface ); 82 } 83 84 static inline IDirectInputDeviceImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface) 85 { 86 return CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface); 87 } 88 89 static const struct dinput_device *dinput_devices[] = 90 { 91 &mouse_device, 92 &keyboard_device, 93 &joystick_linuxinput_device, 94 &joystick_linux_device, 95 &joystick_osx_device 96 }; 97 98 HINSTANCE DINPUT_instance; 99 100 static BOOL check_hook_thread(void); 101 static CRITICAL_SECTION dinput_hook_crit; 102 static struct list direct_input_list = LIST_INIT( direct_input_list ); 103 104 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion); 105 static void uninitialize_directinput_instance(IDirectInputImpl *This); 106 107 static HRESULT create_directinput_instance(REFIID riid, LPVOID *ppDI, IDirectInputImpl **out) 108 { 109 IDirectInputImpl *This = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectInputImpl) ); 110 HRESULT hr; 111 112 if (!This) 113 return E_OUTOFMEMORY; 114 115 This->IDirectInput7A_iface.lpVtbl = &ddi7avt; 116 This->IDirectInput7W_iface.lpVtbl = &ddi7wvt; 117 This->IDirectInput8A_iface.lpVtbl = &ddi8avt; 118 This->IDirectInput8W_iface.lpVtbl = &ddi8wvt; 119 This->IDirectInputJoyConfig8_iface.lpVtbl = &JoyConfig8vt; 120 121 hr = IDirectInput_QueryInterface( &This->IDirectInput7A_iface, riid, ppDI ); 122 if (FAILED(hr)) 123 { 124 HeapFree( GetProcessHeap(), 0, This ); 125 return hr; 126 } 127 128 if (out) *out = This; 129 return DI_OK; 130 } 131 132 /****************************************************************************** 133 * DirectInputCreateEx (DINPUT.@) 134 */ 135 HRESULT WINAPI DirectInputCreateEx( 136 HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI, 137 LPUNKNOWN punkOuter) 138 { 139 IDirectInputImpl *This; 140 HRESULT hr; 141 142 TRACE("(%p,%04x,%s,%p,%p)\n", hinst, dwVersion, debugstr_guid(riid), ppDI, punkOuter); 143 144 if (IsEqualGUID( &IID_IDirectInputA, riid ) || 145 IsEqualGUID( &IID_IDirectInput2A, riid ) || 146 IsEqualGUID( &IID_IDirectInput7A, riid ) || 147 IsEqualGUID( &IID_IDirectInputW, riid ) || 148 IsEqualGUID( &IID_IDirectInput2W, riid ) || 149 IsEqualGUID( &IID_IDirectInput7W, riid )) 150 { 151 hr = create_directinput_instance(riid, ppDI, &This); 152 if (FAILED(hr)) 153 return hr; 154 } 155 else 156 return DIERR_NOINTERFACE; 157 158 hr = IDirectInput_Initialize( &This->IDirectInput7A_iface, hinst, dwVersion ); 159 if (FAILED(hr)) 160 { 161 IDirectInput_Release( &This->IDirectInput7A_iface ); 162 *ppDI = NULL; 163 return hr; 164 } 165 166 return DI_OK; 167 } 168 169 /****************************************************************************** 170 * DirectInput8Create (DINPUT8.@) 171 */ 172 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInput8Create(HINSTANCE hinst, 173 DWORD version, REFIID iid, void **out, IUnknown *outer) 174 { 175 IDirectInputImpl *This; 176 HRESULT hr; 177 178 TRACE("hinst %p, version %#x, iid %s, out %p, outer %p.\n", 179 hinst, version, debugstr_guid(iid), out, outer); 180 181 if (!out) 182 return E_POINTER; 183 184 if (!IsEqualGUID(&IID_IDirectInput8A, iid) && 185 !IsEqualGUID(&IID_IDirectInput8W, iid) && 186 !IsEqualGUID(&IID_IUnknown, iid)) 187 { 188 *out = NULL; 189 return DIERR_NOINTERFACE; 190 } 191 192 hr = create_directinput_instance(iid, out, &This); 193 194 if (FAILED(hr)) 195 { 196 ERR("Failed to create DirectInput, hr %#x.\n", hr); 197 return hr; 198 } 199 200 /* When aggregation is used, the application needs to manually call Initialize(). */ 201 if (!outer && IsEqualGUID(&IID_IDirectInput8A, iid)) 202 { 203 hr = IDirectInput8_Initialize(&This->IDirectInput8A_iface, hinst, version); 204 if (FAILED(hr)) 205 { 206 IDirectInput8_Release(&This->IDirectInput8A_iface); 207 *out = NULL; 208 return hr; 209 } 210 } 211 212 if (!outer && IsEqualGUID(&IID_IDirectInput8W, iid)) 213 { 214 hr = IDirectInput8_Initialize(&This->IDirectInput8W_iface, hinst, version); 215 if (FAILED(hr)) 216 { 217 IDirectInput8_Release(&This->IDirectInput8W_iface); 218 *out = NULL; 219 return hr; 220 } 221 } 222 223 return S_OK; 224 } 225 226 /****************************************************************************** 227 * DirectInputCreateA (DINPUT.@) 228 */ 229 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter) 230 { 231 return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7A, (LPVOID *)ppDI, punkOuter); 232 } 233 234 /****************************************************************************** 235 * DirectInputCreateW (DINPUT.@) 236 */ 237 HRESULT WINAPI DECLSPEC_HOTPATCH DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter) 238 { 239 return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter); 240 } 241 242 static const char *_dump_DIDEVTYPE_value(DWORD dwDevType, DWORD dwVersion) 243 { 244 if (dwVersion < 0x0800) { 245 switch (dwDevType) { 246 case 0: return "All devices"; 247 case DIDEVTYPE_MOUSE: return "DIDEVTYPE_MOUSE"; 248 case DIDEVTYPE_KEYBOARD: return "DIDEVTYPE_KEYBOARD"; 249 case DIDEVTYPE_JOYSTICK: return "DIDEVTYPE_JOYSTICK"; 250 case DIDEVTYPE_DEVICE: return "DIDEVTYPE_DEVICE"; 251 default: return "Unknown"; 252 } 253 } else { 254 switch (dwDevType) { 255 case DI8DEVCLASS_ALL: return "All devices"; 256 case DI8DEVCLASS_POINTER: return "DI8DEVCLASS_POINTER"; 257 case DI8DEVCLASS_KEYBOARD: return "DI8DEVCLASS_KEYBOARD"; 258 case DI8DEVCLASS_DEVICE: return "DI8DEVCLASS_DEVICE"; 259 case DI8DEVCLASS_GAMECTRL: return "DI8DEVCLASS_GAMECTRL"; 260 default: return "Unknown"; 261 } 262 } 263 } 264 265 static void _dump_EnumDevices_dwFlags(DWORD dwFlags) 266 { 267 if (TRACE_ON(dinput)) { 268 unsigned int i; 269 static const struct { 270 DWORD mask; 271 const char *name; 272 } flags[] = { 273 #define FE(x) { x, #x} 274 FE(DIEDFL_ALLDEVICES), 275 FE(DIEDFL_ATTACHEDONLY), 276 FE(DIEDFL_FORCEFEEDBACK), 277 FE(DIEDFL_INCLUDEALIASES), 278 FE(DIEDFL_INCLUDEPHANTOMS), 279 FE(DIEDFL_INCLUDEHIDDEN) 280 #undef FE 281 }; 282 TRACE(" flags: "); 283 if (dwFlags == 0) { 284 TRACE("DIEDFL_ALLDEVICES\n"); 285 return; 286 } 287 for (i = 0; i < ARRAY_SIZE(flags); i++) 288 if (flags[i].mask & dwFlags) 289 TRACE("%s ",flags[i].name); 290 } 291 TRACE("\n"); 292 } 293 294 static const char *dump_semantic(DWORD semantic) 295 { 296 if((semantic & 0xff000000) == 0xff000000) 297 return "Any AXIS"; 298 else if((semantic & 0x82000000) == 0x82000000) 299 return "Mouse"; 300 else if((semantic & 0x81000000) == 0x81000000) 301 return "Keybaord"; 302 else if((semantic & DIVIRTUAL_FLYING_HELICOPTER) == DIVIRTUAL_FLYING_HELICOPTER) 303 return "Helicopter"; 304 305 return "Unknown"; 306 } 307 308 static void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat) 309 { 310 unsigned int i; 311 312 TRACE("diaf.dwSize = %d\n", lpdiActionFormat->dwSize); 313 TRACE("diaf.dwActionSize = %d\n", lpdiActionFormat->dwActionSize); 314 TRACE("diaf.dwDataSize = %d\n", lpdiActionFormat->dwDataSize); 315 TRACE("diaf.dwNumActions = %d\n", lpdiActionFormat->dwNumActions); 316 TRACE("diaf.rgoAction = %p\n", lpdiActionFormat->rgoAction); 317 TRACE("diaf.guidActionMap = %s\n", debugstr_guid(&lpdiActionFormat->guidActionMap)); 318 TRACE("diaf.dwGenre = 0x%08x\n", lpdiActionFormat->dwGenre); 319 TRACE("diaf.dwBufferSize = %d\n", lpdiActionFormat->dwBufferSize); 320 TRACE("diaf.lAxisMin = %d\n", lpdiActionFormat->lAxisMin); 321 TRACE("diaf.lAxisMax = %d\n", lpdiActionFormat->lAxisMax); 322 TRACE("diaf.hInstString = %p\n", lpdiActionFormat->hInstString); 323 TRACE("diaf.ftTimeStamp ...\n"); 324 TRACE("diaf.dwCRC = 0x%x\n", lpdiActionFormat->dwCRC); 325 TRACE("diaf.tszActionMap = %s\n", debugstr_a(lpdiActionFormat->tszActionMap)); 326 for (i = 0; i < lpdiActionFormat->dwNumActions; i++) 327 { 328 TRACE("diaf.rgoAction[%u]:\n", i); 329 TRACE("\tuAppData=0x%lx\n", lpdiActionFormat->rgoAction[i].uAppData); 330 TRACE("\tdwSemantic=0x%08x (%s)\n", lpdiActionFormat->rgoAction[i].dwSemantic, dump_semantic(lpdiActionFormat->rgoAction[i].dwSemantic)); 331 TRACE("\tdwFlags=0x%x\n", lpdiActionFormat->rgoAction[i].dwFlags); 332 TRACE("\tszActionName=%s\n", debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName)); 333 TRACE("\tguidInstance=%s\n", debugstr_guid(&lpdiActionFormat->rgoAction[i].guidInstance)); 334 TRACE("\tdwObjID=0x%x\n", lpdiActionFormat->rgoAction[i].dwObjID); 335 TRACE("\tdwHow=0x%x\n", lpdiActionFormat->rgoAction[i].dwHow); 336 } 337 } 338 339 void _copy_diactionformatAtoW(LPDIACTIONFORMATW to, LPDIACTIONFORMATA from) 340 { 341 int i; 342 343 to->dwSize = sizeof(DIACTIONFORMATW); 344 to->dwActionSize = sizeof(DIACTIONW); 345 to->dwDataSize = from->dwDataSize; 346 to->dwNumActions = from->dwNumActions; 347 to->guidActionMap = from->guidActionMap; 348 to->dwGenre = from->dwGenre; 349 to->dwBufferSize = from->dwBufferSize; 350 to->lAxisMin = from->lAxisMin; 351 to->lAxisMax = from->lAxisMax; 352 to->dwCRC = from->dwCRC; 353 to->ftTimeStamp = from->ftTimeStamp; 354 355 for (i=0; i < to->dwNumActions; i++) 356 { 357 to->rgoAction[i].uAppData = from->rgoAction[i].uAppData; 358 to->rgoAction[i].dwSemantic = from->rgoAction[i].dwSemantic; 359 to->rgoAction[i].dwFlags = from->rgoAction[i].dwFlags; 360 to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance; 361 to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID; 362 to->rgoAction[i].dwHow = from->rgoAction[i].dwHow; 363 } 364 } 365 366 void _copy_diactionformatWtoA(LPDIACTIONFORMATA to, LPDIACTIONFORMATW from) 367 { 368 int i; 369 370 to->dwSize = sizeof(DIACTIONFORMATA); 371 to->dwActionSize = sizeof(DIACTIONA); 372 to->dwDataSize = from->dwDataSize; 373 to->dwNumActions = from->dwNumActions; 374 to->guidActionMap = from->guidActionMap; 375 to->dwGenre = from->dwGenre; 376 to->dwBufferSize = from->dwBufferSize; 377 to->lAxisMin = from->lAxisMin; 378 to->lAxisMax = from->lAxisMax; 379 to->dwCRC = from->dwCRC; 380 to->ftTimeStamp = from->ftTimeStamp; 381 382 for (i=0; i < to->dwNumActions; i++) 383 { 384 to->rgoAction[i].uAppData = from->rgoAction[i].uAppData; 385 to->rgoAction[i].dwSemantic = from->rgoAction[i].dwSemantic; 386 to->rgoAction[i].dwFlags = from->rgoAction[i].dwFlags; 387 to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance; 388 to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID; 389 to->rgoAction[i].dwHow = from->rgoAction[i].dwHow; 390 } 391 } 392 393 /* diactionformat_priority 394 * 395 * Given a DIACTIONFORMAT structure and a DI genre, returns the enumeration 396 * priority. Joysticks should pass the game genre, and mouse or keyboard their 397 * respective DI*_MASK 398 */ 399 static DWORD diactionformat_priorityA(LPDIACTIONFORMATA lpdiaf, DWORD genre) 400 { 401 int i; 402 DWORD priorityFlags = 0; 403 404 /* If there's at least one action for the device it's priority 1 */ 405 for(i=0; i < lpdiaf->dwNumActions; i++) 406 if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre) 407 priorityFlags |= DIEDBS_MAPPEDPRI1; 408 409 return priorityFlags; 410 } 411 412 static DWORD diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf, DWORD genre) 413 { 414 int i; 415 DWORD priorityFlags = 0; 416 417 /* If there's at least one action for the device it's priority 1 */ 418 for(i=0; i < lpdiaf->dwNumActions; i++) 419 if ((lpdiaf->rgoAction[i].dwSemantic & genre) == genre) 420 priorityFlags |= DIEDBS_MAPPEDPRI1; 421 422 return priorityFlags; 423 } 424 425 #if defined __i386__ && defined _MSC_VER 426 __declspec(naked) BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref) 427 { 428 __asm 429 { 430 push ebp 431 mov ebp, esp 432 push [ebp+16] 433 push [ebp+12] 434 call [ebp+8] 435 leave 436 ret 437 } 438 } 439 #elif defined __i386__ && defined __GNUC__ 440 extern BOOL enum_callback_wrapper(void *callback, const void *instance, void *ref); 441 __ASM_GLOBAL_FUNC( enum_callback_wrapper, 442 "pushl %ebp\n\t" 443 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") 444 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") 445 "movl %esp,%ebp\n\t" 446 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") 447 "pushl 16(%ebp)\n\t" 448 "pushl 12(%ebp)\n\t" 449 "call *8(%ebp)\n\t" 450 "leave\n\t" 451 __ASM_CFI(".cfi_def_cfa %esp,4\n\t") 452 __ASM_CFI(".cfi_same_value %ebp\n\t") 453 "ret" ) 454 #else 455 #define enum_callback_wrapper(callback, instance, ref) (callback)((instance), (ref)) 456 #endif 457 458 /****************************************************************************** 459 * IDirectInputA_EnumDevices 460 */ 461 static HRESULT WINAPI IDirectInputAImpl_EnumDevices( 462 LPDIRECTINPUT7A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, 463 LPVOID pvRef, DWORD dwFlags) 464 { 465 IDirectInputImpl *This = impl_from_IDirectInput7A(iface); 466 DIDEVICEINSTANCEA devInstance; 467 unsigned int i; 468 int j; 469 HRESULT r; 470 471 TRACE("(this=%p,0x%04x '%s',%p,%p,0x%04x)\n", 472 This, dwDevType, _dump_DIDEVTYPE_value(dwDevType, This->dwVersion), 473 lpCallback, pvRef, dwFlags); 474 _dump_EnumDevices_dwFlags(dwFlags); 475 476 if (!lpCallback || 477 dwFlags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN) || 478 (dwDevType > DI8DEVCLASS_GAMECTRL && dwDevType < DI8DEVTYPE_DEVICE) || dwDevType > DI8DEVTYPE_SUPPLEMENTAL) 479 return DIERR_INVALIDPARAM; 480 481 if (!This->initialized) 482 return DIERR_NOTINITIALIZED; 483 484 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) { 485 if (!dinput_devices[i]->enum_deviceA) continue; 486 487 TRACE(" Checking device %u ('%s')\n", i, dinput_devices[i]->name); 488 for (j = 0, r = S_OK; SUCCEEDED(r); j++) { 489 devInstance.dwSize = sizeof(devInstance); 490 r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j); 491 if (r == S_OK) 492 if (enum_callback_wrapper(lpCallback, &devInstance, pvRef) == DIENUM_STOP) 493 return S_OK; 494 } 495 } 496 497 return S_OK; 498 } 499 /****************************************************************************** 500 * IDirectInputW_EnumDevices 501 */ 502 static HRESULT WINAPI IDirectInputWImpl_EnumDevices( 503 LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, 504 LPVOID pvRef, DWORD dwFlags) 505 { 506 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 507 DIDEVICEINSTANCEW devInstance; 508 unsigned int i; 509 int j; 510 HRESULT r; 511 512 TRACE("(this=%p,0x%04x '%s',%p,%p,0x%04x)\n", 513 This, dwDevType, _dump_DIDEVTYPE_value(dwDevType, This->dwVersion), 514 lpCallback, pvRef, dwFlags); 515 _dump_EnumDevices_dwFlags(dwFlags); 516 517 if (!lpCallback || 518 dwFlags & ~(DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK | DIEDFL_INCLUDEALIASES | DIEDFL_INCLUDEPHANTOMS | DIEDFL_INCLUDEHIDDEN) || 519 (dwDevType > DI8DEVCLASS_GAMECTRL && dwDevType < DI8DEVTYPE_DEVICE) || dwDevType > DI8DEVTYPE_SUPPLEMENTAL) 520 return DIERR_INVALIDPARAM; 521 522 if (!This->initialized) 523 return DIERR_NOTINITIALIZED; 524 525 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) { 526 if (!dinput_devices[i]->enum_deviceW) continue; 527 for (j = 0, r = S_OK; SUCCEEDED(r); j++) { 528 devInstance.dwSize = sizeof(devInstance); 529 TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name); 530 r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j); 531 if (r == S_OK) 532 if (enum_callback_wrapper(lpCallback, &devInstance, pvRef) == DIENUM_STOP) 533 return S_OK; 534 } 535 } 536 537 return S_OK; 538 } 539 540 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface) 541 { 542 IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 543 ULONG ref = InterlockedIncrement(&This->ref); 544 545 TRACE( "(%p) ref %d\n", This, ref ); 546 return ref; 547 } 548 549 static ULONG WINAPI IDirectInputWImpl_AddRef(LPDIRECTINPUT7W iface) 550 { 551 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 552 return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface ); 553 } 554 555 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface) 556 { 557 IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 558 ULONG ref = InterlockedDecrement( &This->ref ); 559 560 TRACE( "(%p) ref %d\n", This, ref ); 561 562 if (ref == 0) 563 { 564 uninitialize_directinput_instance( This ); 565 HeapFree( GetProcessHeap(), 0, This ); 566 } 567 568 return ref; 569 } 570 571 static ULONG WINAPI IDirectInputWImpl_Release(LPDIRECTINPUT7W iface) 572 { 573 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 574 return IDirectInputAImpl_Release( &This->IDirectInput7A_iface ); 575 } 576 577 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj) 578 { 579 IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 580 581 TRACE( "(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj ); 582 583 if (!riid || !ppobj) 584 return E_POINTER; 585 586 *ppobj = NULL; 587 588 #if DIRECTINPUT_VERSION == 0x0700 589 if (IsEqualGUID( &IID_IUnknown, riid ) || 590 IsEqualGUID( &IID_IDirectInputA, riid ) || 591 IsEqualGUID( &IID_IDirectInput2A, riid ) || 592 IsEqualGUID( &IID_IDirectInput7A, riid )) 593 *ppobj = &This->IDirectInput7A_iface; 594 else if (IsEqualGUID( &IID_IDirectInputW, riid ) || 595 IsEqualGUID( &IID_IDirectInput2W, riid ) || 596 IsEqualGUID( &IID_IDirectInput7W, riid )) 597 *ppobj = &This->IDirectInput7W_iface; 598 599 #else 600 if (IsEqualGUID( &IID_IUnknown, riid ) || 601 IsEqualGUID( &IID_IDirectInput8A, riid )) 602 *ppobj = &This->IDirectInput8A_iface; 603 604 else if (IsEqualGUID( &IID_IDirectInput8W, riid )) 605 *ppobj = &This->IDirectInput8W_iface; 606 607 #endif 608 609 if (IsEqualGUID( &IID_IDirectInputJoyConfig8, riid )) 610 *ppobj = &This->IDirectInputJoyConfig8_iface; 611 612 if(*ppobj) 613 { 614 IUnknown_AddRef( (IUnknown*)*ppobj ); 615 return DI_OK; 616 } 617 618 WARN( "Unsupported interface: %s\n", debugstr_guid(riid)); 619 return E_NOINTERFACE; 620 } 621 622 static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj) 623 { 624 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 625 return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj ); 626 } 627 628 static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwVersion) 629 { 630 if (!This->initialized) 631 { 632 This->dwVersion = dwVersion; 633 This->evsequence = 1; 634 635 InitializeCriticalSection( &This->crit ); 636 This->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectInputImpl*->crit"); 637 638 list_init( &This->devices_list ); 639 list_init( &This->device_players ); 640 641 /* Add self to the list of the IDirectInputs */ 642 EnterCriticalSection( &dinput_hook_crit ); 643 list_add_head( &direct_input_list, &This->entry ); 644 LeaveCriticalSection( &dinput_hook_crit ); 645 646 This->initialized = TRUE; 647 648 if (!check_hook_thread()) 649 { 650 uninitialize_directinput_instance( This ); 651 return DIERR_GENERIC; 652 } 653 } 654 655 return DI_OK; 656 } 657 658 static void uninitialize_directinput_instance(IDirectInputImpl *This) 659 { 660 if (This->initialized) 661 { 662 struct DevicePlayer *device_player, *device_player2; 663 /* Remove self from the list of the IDirectInputs */ 664 EnterCriticalSection( &dinput_hook_crit ); 665 list_remove( &This->entry ); 666 LeaveCriticalSection( &dinput_hook_crit ); 667 668 LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2, 669 &This->device_players, struct DevicePlayer, entry ) 670 HeapFree(GetProcessHeap(), 0, device_player); 671 672 check_hook_thread(); 673 674 This->crit.DebugInfo->Spare[0] = 0; 675 DeleteCriticalSection( &This->crit ); 676 677 This->initialized = FALSE; 678 } 679 } 680 681 enum directinput_versions 682 { 683 DIRECTINPUT_VERSION_300 = 0x0300, 684 DIRECTINPUT_VERSION_500 = 0x0500, 685 DIRECTINPUT_VERSION_50A = 0x050A, 686 DIRECTINPUT_VERSION_5B2 = 0x05B2, 687 DIRECTINPUT_VERSION_602 = 0x0602, 688 DIRECTINPUT_VERSION_61A = 0x061A, 689 DIRECTINPUT_VERSION_700 = 0x0700, 690 }; 691 692 static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD version) 693 { 694 IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 695 696 TRACE("(%p)->(%p, 0x%04x)\n", This, hinst, version); 697 698 if (!hinst) 699 return DIERR_INVALIDPARAM; 700 else if (version == 0) 701 return DIERR_NOTINITIALIZED; 702 else if (version > DIRECTINPUT_VERSION_700) 703 return DIERR_OLDDIRECTINPUTVERSION; 704 else if (version != DIRECTINPUT_VERSION_300 && version != DIRECTINPUT_VERSION_500 && 705 version != DIRECTINPUT_VERSION_50A && version != DIRECTINPUT_VERSION_5B2 && 706 version != DIRECTINPUT_VERSION_602 && version != DIRECTINPUT_VERSION_61A && 707 version != DIRECTINPUT_VERSION_700 && version != DIRECTINPUT_VERSION) 708 return DIERR_BETADIRECTINPUTVERSION; 709 710 return initialize_directinput_instance(This, version); 711 } 712 713 static HRESULT WINAPI IDirectInputWImpl_Initialize(LPDIRECTINPUT7W iface, HINSTANCE hinst, DWORD x) 714 { 715 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 716 return IDirectInputAImpl_Initialize( &This->IDirectInput7A_iface, hinst, x ); 717 } 718 719 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, REFGUID rguid) 720 { 721 IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 722 HRESULT hr; 723 LPDIRECTINPUTDEVICEA device; 724 725 TRACE( "(%p)->(%s)\n", This, debugstr_guid(rguid) ); 726 727 if (!rguid) return E_POINTER; 728 if (!This->initialized) 729 return DIERR_NOTINITIALIZED; 730 731 hr = IDirectInput_CreateDevice( iface, rguid, &device, NULL ); 732 if (hr != DI_OK) return DI_NOTATTACHED; 733 734 IUnknown_Release( device ); 735 736 return DI_OK; 737 } 738 739 static HRESULT WINAPI IDirectInputWImpl_GetDeviceStatus(LPDIRECTINPUT7W iface, REFGUID rguid) 740 { 741 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 742 return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid ); 743 } 744 745 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface, 746 HWND hwndOwner, 747 DWORD dwFlags) 748 { 749 WCHAR control_exeW[] = {'c','o','n','t','r','o','l','.','e','x','e',0}; 750 STARTUPINFOW si = {0}; 751 PROCESS_INFORMATION pi; 752 753 IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 754 755 TRACE( "(%p)->(%p, %08x)\n", This, hwndOwner, dwFlags ); 756 757 if (hwndOwner && !IsWindow(hwndOwner)) 758 return E_HANDLE; 759 760 if (dwFlags) 761 return DIERR_INVALIDPARAM; 762 763 if (!This->initialized) 764 return DIERR_NOTINITIALIZED; 765 766 if (!CreateProcessW(NULL, control_exeW, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &si, &pi)) 767 return HRESULT_FROM_WIN32(GetLastError()); 768 769 return DI_OK; 770 } 771 772 static HRESULT WINAPI IDirectInputWImpl_RunControlPanel(LPDIRECTINPUT7W iface, HWND hwndOwner, DWORD dwFlags) 773 { 774 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 775 return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags ); 776 } 777 778 static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid, 779 LPCSTR pszName, LPGUID pguidInstance) 780 { 781 IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 782 783 FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance ); 784 785 return DI_OK; 786 } 787 788 static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid, 789 LPCWSTR pszName, LPGUID pguidInstance) 790 { 791 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 792 793 FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance ); 794 795 return DI_OK; 796 } 797 798 static HRESULT create_device(IDirectInputImpl *This, REFGUID rguid, REFIID riid, LPVOID *pvOut, BOOL unicode) 799 { 800 unsigned int i; 801 802 if (pvOut) 803 *pvOut = NULL; 804 805 if (!rguid || !pvOut) 806 return E_POINTER; 807 808 if (!This->initialized) 809 return DIERR_NOTINITIALIZED; 810 811 /* Loop on all the devices to see if anyone matches the given GUID */ 812 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) 813 { 814 HRESULT ret; 815 816 if (!dinput_devices[i]->create_device) continue; 817 if ((ret = dinput_devices[i]->create_device(This, rguid, riid, pvOut, unicode)) == DI_OK) 818 return DI_OK; 819 } 820 821 WARN("invalid device GUID %s\n", debugstr_guid(rguid)); 822 return DIERR_DEVICENOTREG; 823 } 824 825 static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid, 826 REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) 827 { 828 IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 829 830 TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); 831 832 return create_device(This, rguid, riid, pvOut, FALSE); 833 } 834 835 static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid, 836 REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) 837 { 838 IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); 839 840 TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); 841 842 return create_device(This, rguid, riid, pvOut, TRUE); 843 } 844 845 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(LPDIRECTINPUT7A iface, REFGUID rguid, 846 LPDIRECTINPUTDEVICEA* pdev, LPUNKNOWN punk) 847 { 848 return IDirectInput7AImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk); 849 } 850 851 static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface, REFGUID rguid, 852 LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk) 853 { 854 return IDirectInput7WImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk); 855 } 856 857 /******************************************************************************* 858 * DirectInput8 859 */ 860 861 static ULONG WINAPI IDirectInput8AImpl_AddRef(LPDIRECTINPUT8A iface) 862 { 863 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 864 return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface ); 865 } 866 867 static ULONG WINAPI IDirectInput8WImpl_AddRef(LPDIRECTINPUT8W iface) 868 { 869 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 870 return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface ); 871 } 872 873 static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj) 874 { 875 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 876 return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj ); 877 } 878 879 static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj) 880 { 881 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 882 return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj ); 883 } 884 885 static ULONG WINAPI IDirectInput8AImpl_Release(LPDIRECTINPUT8A iface) 886 { 887 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 888 return IDirectInputAImpl_Release( &This->IDirectInput7A_iface ); 889 } 890 891 static ULONG WINAPI IDirectInput8WImpl_Release(LPDIRECTINPUT8W iface) 892 { 893 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 894 return IDirectInputAImpl_Release( &This->IDirectInput7A_iface ); 895 } 896 897 static HRESULT WINAPI IDirectInput8AImpl_CreateDevice(LPDIRECTINPUT8A iface, REFGUID rguid, 898 LPDIRECTINPUTDEVICE8A* pdev, LPUNKNOWN punk) 899 { 900 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 901 return IDirectInput7AImpl_CreateDeviceEx( &This->IDirectInput7A_iface, rguid, NULL, (LPVOID*)pdev, punk ); 902 } 903 904 static HRESULT WINAPI IDirectInput8WImpl_CreateDevice(LPDIRECTINPUT8W iface, REFGUID rguid, 905 LPDIRECTINPUTDEVICE8W* pdev, LPUNKNOWN punk) 906 { 907 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 908 return IDirectInput7WImpl_CreateDeviceEx( &This->IDirectInput7W_iface, rguid, NULL, (LPVOID*)pdev, punk ); 909 } 910 911 static HRESULT WINAPI IDirectInput8AImpl_EnumDevices(LPDIRECTINPUT8A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, 912 LPVOID pvRef, DWORD dwFlags) 913 { 914 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 915 return IDirectInputAImpl_EnumDevices( &This->IDirectInput7A_iface, dwDevType, lpCallback, pvRef, dwFlags ); 916 } 917 918 static HRESULT WINAPI IDirectInput8WImpl_EnumDevices(LPDIRECTINPUT8W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, 919 LPVOID pvRef, DWORD dwFlags) 920 { 921 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 922 return IDirectInputWImpl_EnumDevices( &This->IDirectInput7W_iface, dwDevType, lpCallback, pvRef, dwFlags ); 923 } 924 925 static HRESULT WINAPI IDirectInput8AImpl_GetDeviceStatus(LPDIRECTINPUT8A iface, REFGUID rguid) 926 { 927 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 928 return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid ); 929 } 930 931 static HRESULT WINAPI IDirectInput8WImpl_GetDeviceStatus(LPDIRECTINPUT8W iface, REFGUID rguid) 932 { 933 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 934 return IDirectInputAImpl_GetDeviceStatus( &This->IDirectInput7A_iface, rguid ); 935 } 936 937 static HRESULT WINAPI IDirectInput8AImpl_RunControlPanel(LPDIRECTINPUT8A iface, HWND hwndOwner, DWORD dwFlags) 938 { 939 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 940 return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags ); 941 } 942 943 static HRESULT WINAPI IDirectInput8WImpl_RunControlPanel(LPDIRECTINPUT8W iface, HWND hwndOwner, DWORD dwFlags) 944 { 945 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 946 return IDirectInputAImpl_RunControlPanel( &This->IDirectInput7A_iface, hwndOwner, dwFlags ); 947 } 948 949 static HRESULT WINAPI IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A iface, HINSTANCE hinst, DWORD version) 950 { 951 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 952 953 TRACE("(%p)->(%p, 0x%04x)\n", This, hinst, version); 954 955 if (!hinst) 956 return DIERR_INVALIDPARAM; 957 else if (version == 0) 958 return DIERR_NOTINITIALIZED; 959 else if (version < DIRECTINPUT_VERSION) 960 return DIERR_BETADIRECTINPUTVERSION; 961 else if (version > DIRECTINPUT_VERSION) 962 return DIERR_OLDDIRECTINPUTVERSION; 963 964 return initialize_directinput_instance(This, version); 965 } 966 967 static HRESULT WINAPI IDirectInput8WImpl_Initialize(LPDIRECTINPUT8W iface, HINSTANCE hinst, DWORD version) 968 { 969 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 970 return IDirectInput8AImpl_Initialize( &This->IDirectInput8A_iface, hinst, version ); 971 } 972 973 static HRESULT WINAPI IDirectInput8AImpl_FindDevice(LPDIRECTINPUT8A iface, REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) 974 { 975 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 976 return IDirectInput2AImpl_FindDevice( &This->IDirectInput7A_iface, rguid, pszName, pguidInstance ); 977 } 978 979 static HRESULT WINAPI IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface, REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) 980 { 981 IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); 982 return IDirectInput2WImpl_FindDevice( &This->IDirectInput7W_iface, rguid, pszName, pguidInstance ); 983 } 984 985 static BOOL should_enumerate_device(const WCHAR *username, DWORD dwFlags, 986 struct list *device_players, REFGUID guid) 987 { 988 BOOL should_enumerate = TRUE; 989 struct DevicePlayer *device_player; 990 991 /* Check if user owns this device */ 992 if (dwFlags & DIEDBSFL_THISUSER && username && *username) 993 { 994 should_enumerate = FALSE; 995 LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry) 996 { 997 if (IsEqualGUID(&device_player->instance_guid, guid)) 998 { 999 if (*device_player->username && !lstrcmpW(username, device_player->username)) 1000 return TRUE; /* Device username matches */ 1001 break; 1002 } 1003 } 1004 } 1005 1006 /* Check if this device is not owned by anyone */ 1007 if (dwFlags & DIEDBSFL_AVAILABLEDEVICES) { 1008 BOOL found = FALSE; 1009 should_enumerate = FALSE; 1010 LIST_FOR_EACH_ENTRY(device_player, device_players, struct DevicePlayer, entry) 1011 { 1012 if (IsEqualGUID(&device_player->instance_guid, guid)) 1013 { 1014 if (*device_player->username) 1015 found = TRUE; 1016 break; 1017 } 1018 } 1019 if (!found) 1020 return TRUE; /* Device does not have a username */ 1021 } 1022 1023 return should_enumerate; 1024 } 1025 1026 static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics( 1027 LPDIRECTINPUT8A iface, LPCSTR ptszUserName, LPDIACTIONFORMATA lpdiActionFormat, 1028 LPDIENUMDEVICESBYSEMANTICSCBA lpCallback, 1029 LPVOID pvRef, DWORD dwFlags 1030 ) 1031 { 1032 static REFGUID guids[2] = { &GUID_SysKeyboard, &GUID_SysMouse }; 1033 static const DWORD actionMasks[] = { DIKEYBOARD_MASK, DIMOUSE_MASK }; 1034 IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 1035 DIDEVICEINSTANCEA didevi; 1036 LPDIRECTINPUTDEVICE8A lpdid; 1037 DWORD callbackFlags; 1038 int i, j; 1039 int device_count = 0; 1040 int remain; 1041 DIDEVICEINSTANCEA *didevis = 0; 1042 WCHAR *username_w = 0; 1043 1044 FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_a(ptszUserName), lpdiActionFormat, 1045 lpCallback, pvRef, dwFlags); 1046 #define X(x) if (dwFlags & x) FIXME("\tdwFlags |= "#x"\n"); 1047 X(DIEDBSFL_ATTACHEDONLY) 1048 X(DIEDBSFL_THISUSER) 1049 X(DIEDBSFL_FORCEFEEDBACK) 1050 X(DIEDBSFL_AVAILABLEDEVICES) 1051 X(DIEDBSFL_MULTIMICEKEYBOARDS) 1052 X(DIEDBSFL_NONGAMINGDEVICES) 1053 #undef X 1054 1055 _dump_diactionformatA(lpdiActionFormat); 1056 1057 didevi.dwSize = sizeof(didevi); 1058 1059 if (ptszUserName) 1060 { 1061 int len = MultiByteToWideChar(CP_ACP, 0, ptszUserName, -1, 0, 0); 1062 1063 username_w = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len); 1064 MultiByteToWideChar(CP_ACP, 0, ptszUserName, -1, username_w, len); 1065 } 1066 1067 /* Enumerate all the joysticks */ 1068 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) 1069 { 1070 HRESULT enumSuccess; 1071 1072 if (!dinput_devices[i]->enum_deviceA) continue; 1073 1074 for (j = 0, enumSuccess = S_OK; SUCCEEDED(enumSuccess); j++) 1075 { 1076 TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name); 1077 1078 /* Default behavior is to enumerate attached game controllers */ 1079 enumSuccess = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j); 1080 if (enumSuccess == S_OK && 1081 should_enumerate_device(username_w, dwFlags, &This->device_players, &didevi.guidInstance)) 1082 { 1083 if (device_count++) 1084 didevis = HeapReAlloc(GetProcessHeap(), 0, didevis, sizeof(DIDEVICEINSTANCEA)*device_count); 1085 else 1086 didevis = HeapAlloc(GetProcessHeap(), 0, sizeof(DIDEVICEINSTANCEA)*device_count); 1087 didevis[device_count-1] = didevi; 1088 } 1089 } 1090 } 1091 1092 remain = device_count; 1093 /* Add keyboard and mouse to remaining device count */ 1094 if (!(dwFlags & DIEDBSFL_FORCEFEEDBACK)) 1095 { 1096 for (i = 0; i < ARRAY_SIZE(guids); i++) 1097 { 1098 if (should_enumerate_device(username_w, dwFlags, &This->device_players, guids[i])) 1099 remain++; 1100 } 1101 } 1102 1103 for (i = 0; i < device_count; i++) 1104 { 1105 callbackFlags = diactionformat_priorityA(lpdiActionFormat, lpdiActionFormat->dwGenre); 1106 IDirectInput_CreateDevice(iface, &didevis[i].guidInstance, &lpdid, NULL); 1107 1108 if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP) 1109 { 1110 IDirectInputDevice_Release(lpdid); 1111 HeapFree(GetProcessHeap(), 0, didevis); 1112 HeapFree(GetProcessHeap(), 0, username_w); 1113 return DI_OK; 1114 } 1115 IDirectInputDevice_Release(lpdid); 1116 } 1117 1118 HeapFree(GetProcessHeap(), 0, didevis); 1119 1120 if (dwFlags & DIEDBSFL_FORCEFEEDBACK) 1121 { 1122 HeapFree(GetProcessHeap(), 0, username_w); 1123 return DI_OK; 1124 } 1125 1126 /* Enumerate keyboard and mouse */ 1127 for (i = 0; i < ARRAY_SIZE(guids); i++) 1128 { 1129 if (should_enumerate_device(username_w, dwFlags, &This->device_players, guids[i])) 1130 { 1131 callbackFlags = diactionformat_priorityA(lpdiActionFormat, actionMasks[i]); 1132 1133 IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL); 1134 IDirectInputDevice_GetDeviceInfo(lpdid, &didevi); 1135 1136 if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP) 1137 { 1138 IDirectInputDevice_Release(lpdid); 1139 HeapFree(GetProcessHeap(), 0, username_w); 1140 return DI_OK; 1141 } 1142 IDirectInputDevice_Release(lpdid); 1143 } 1144 } 1145 1146 HeapFree(GetProcessHeap(), 0, username_w); 1147 return DI_OK; 1148 } 1149 1150 static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics( 1151 LPDIRECTINPUT8W iface, LPCWSTR ptszUserName, LPDIACTIONFORMATW lpdiActionFormat, 1152 LPDIENUMDEVICESBYSEMANTICSCBW lpCallback, 1153 LPVOID pvRef, DWORD dwFlags 1154 ) 1155 { 1156 static REFGUID guids[2] = { &GUID_SysKeyboard, &GUID_SysMouse }; 1157 static const DWORD actionMasks[] = { DIKEYBOARD_MASK, DIMOUSE_MASK }; 1158 IDirectInputImpl *This = impl_from_IDirectInput8W(iface); 1159 DIDEVICEINSTANCEW didevi; 1160 LPDIRECTINPUTDEVICE8W lpdid; 1161 DWORD callbackFlags; 1162 int i, j; 1163 int device_count = 0; 1164 int remain; 1165 DIDEVICEINSTANCEW *didevis = 0; 1166 1167 FIXME("(this=%p,%s,%p,%p,%p,%04x): semi-stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat, 1168 lpCallback, pvRef, dwFlags); 1169 1170 didevi.dwSize = sizeof(didevi); 1171 1172 /* Enumerate all the joysticks */ 1173 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) 1174 { 1175 HRESULT enumSuccess; 1176 1177 if (!dinput_devices[i]->enum_deviceW) continue; 1178 1179 for (j = 0, enumSuccess = S_OK; SUCCEEDED(enumSuccess); j++) 1180 { 1181 TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name); 1182 1183 /* Default behavior is to enumerate attached game controllers */ 1184 enumSuccess = dinput_devices[i]->enum_deviceW(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY | dwFlags, &didevi, This->dwVersion, j); 1185 if (enumSuccess == S_OK && 1186 should_enumerate_device(ptszUserName, dwFlags, &This->device_players, &didevi.guidInstance)) 1187 { 1188 if (device_count++) 1189 didevis = HeapReAlloc(GetProcessHeap(), 0, didevis, sizeof(DIDEVICEINSTANCEW)*device_count); 1190 else 1191 didevis = HeapAlloc(GetProcessHeap(), 0, sizeof(DIDEVICEINSTANCEW)*device_count); 1192 didevis[device_count-1] = didevi; 1193 } 1194 } 1195 } 1196 1197 remain = device_count; 1198 /* Add keyboard and mouse to remaining device count */ 1199 if (!(dwFlags & DIEDBSFL_FORCEFEEDBACK)) 1200 { 1201 for (i = 0; i < ARRAY_SIZE(guids); i++) 1202 { 1203 if (should_enumerate_device(ptszUserName, dwFlags, &This->device_players, guids[i])) 1204 remain++; 1205 } 1206 } 1207 1208 for (i = 0; i < device_count; i++) 1209 { 1210 callbackFlags = diactionformat_priorityW(lpdiActionFormat, lpdiActionFormat->dwGenre); 1211 IDirectInput_CreateDevice(iface, &didevis[i].guidInstance, &lpdid, NULL); 1212 1213 if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP) 1214 { 1215 HeapFree(GetProcessHeap(), 0, didevis); 1216 return DI_OK; 1217 } 1218 } 1219 1220 HeapFree(GetProcessHeap(), 0, didevis); 1221 1222 if (dwFlags & DIEDBSFL_FORCEFEEDBACK) return DI_OK; 1223 1224 /* Enumerate keyboard and mouse */ 1225 for (i = 0; i < ARRAY_SIZE(guids); i++) 1226 { 1227 if (should_enumerate_device(ptszUserName, dwFlags, &This->device_players, guids[i])) 1228 { 1229 callbackFlags = diactionformat_priorityW(lpdiActionFormat, actionMasks[i]); 1230 1231 IDirectInput_CreateDevice(iface, guids[i], &lpdid, NULL); 1232 IDirectInputDevice_GetDeviceInfo(lpdid, &didevi); 1233 1234 if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP) 1235 return DI_OK; 1236 } 1237 } 1238 1239 return DI_OK; 1240 } 1241 1242 static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices( 1243 LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, 1244 LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData 1245 ) 1246 { 1247 IDirectInputImpl *This = impl_from_IDirectInput8W(iface); 1248 1249 FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData); 1250 1251 /* Call helper function in config.c to do the real work */ 1252 return _configure_devices(iface, lpdiCallback, lpdiCDParams, dwFlags, pvRefData); 1253 } 1254 1255 static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices( 1256 LPDIRECTINPUT8A iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, 1257 LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData 1258 ) 1259 { 1260 IDirectInputImpl *This = impl_from_IDirectInput8A(iface); 1261 DIACTIONFORMATW diafW; 1262 DICONFIGUREDEVICESPARAMSW diCDParamsW; 1263 HRESULT hr; 1264 int i; 1265 1266 FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData); 1267 1268 /* Copy parameters */ 1269 diCDParamsW.dwSize = sizeof(DICONFIGUREDEVICESPARAMSW); 1270 diCDParamsW.dwcUsers = lpdiCDParams->dwcUsers; 1271 diCDParamsW.dwcFormats = lpdiCDParams->dwcFormats; 1272 diCDParamsW.lprgFormats = &diafW; 1273 diCDParamsW.hwnd = lpdiCDParams->hwnd; 1274 diCDParamsW.lptszUserNames = NULL; 1275 1276 if (lpdiCDParams->lptszUserNames) { 1277 char *start = lpdiCDParams->lptszUserNames; 1278 WCHAR *to = NULL; 1279 int total_len = 0; 1280 for (i = 0; i < lpdiCDParams->dwcUsers; i++) 1281 { 1282 char *end = start + 1; 1283 int len; 1284 while (*(end++)); 1285 len = MultiByteToWideChar(CP_ACP, 0, start, end - start, NULL, 0); 1286 total_len += len + 2; /* length of string and two null char */ 1287 if (to) 1288 to = HeapReAlloc(GetProcessHeap(), 0, to, sizeof(WCHAR) * total_len); 1289 else 1290 to = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * total_len); 1291 1292 MultiByteToWideChar(CP_ACP, 0, start, end - start, to + (total_len - len - 2), len); 1293 to[total_len] = 0; 1294 to[total_len - 1] = 0; 1295 } 1296 diCDParamsW.lptszUserNames = to; 1297 } 1298 1299 diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiCDParams->lprgFormats->dwNumActions); 1300 _copy_diactionformatAtoW(&diafW, lpdiCDParams->lprgFormats); 1301 1302 /* Copy action names */ 1303 for (i=0; i < diafW.dwNumActions; i++) 1304 { 1305 const char* from = lpdiCDParams->lprgFormats->rgoAction[i].u.lptszActionName; 1306 int len = MultiByteToWideChar(CP_ACP, 0, from , -1, NULL , 0); 1307 WCHAR *to = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*len); 1308 1309 MultiByteToWideChar(CP_ACP, 0, from , -1, to , len); 1310 diafW.rgoAction[i].u.lptszActionName = to; 1311 } 1312 1313 hr = IDirectInput8WImpl_ConfigureDevices(&This->IDirectInput8W_iface, lpdiCallback, &diCDParamsW, dwFlags, pvRefData); 1314 1315 /* Copy back configuration */ 1316 if (SUCCEEDED(hr)) 1317 _copy_diactionformatWtoA(lpdiCDParams->lprgFormats, &diafW); 1318 1319 /* Free memory */ 1320 for (i=0; i < diafW.dwNumActions; i++) 1321 HeapFree(GetProcessHeap(), 0, (void*) diafW.rgoAction[i].u.lptszActionName); 1322 1323 HeapFree(GetProcessHeap(), 0, diafW.rgoAction); 1324 1325 heap_free((void*) diCDParamsW.lptszUserNames); 1326 1327 return hr; 1328 } 1329 1330 /***************************************************************************** 1331 * IDirectInputJoyConfig8 interface 1332 */ 1333 1334 static inline IDirectInputImpl *impl_from_IDirectInputJoyConfig8(IDirectInputJoyConfig8 *iface) 1335 { 1336 return CONTAINING_RECORD( iface, IDirectInputImpl, IDirectInputJoyConfig8_iface ); 1337 } 1338 1339 static HRESULT WINAPI JoyConfig8Impl_QueryInterface(IDirectInputJoyConfig8 *iface, REFIID riid, void** ppobj) 1340 { 1341 IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface ); 1342 return IDirectInputAImpl_QueryInterface( &This->IDirectInput7A_iface, riid, ppobj ); 1343 } 1344 1345 static ULONG WINAPI JoyConfig8Impl_AddRef(IDirectInputJoyConfig8 *iface) 1346 { 1347 IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface ); 1348 return IDirectInputAImpl_AddRef( &This->IDirectInput7A_iface ); 1349 } 1350 1351 static ULONG WINAPI JoyConfig8Impl_Release(IDirectInputJoyConfig8 *iface) 1352 { 1353 IDirectInputImpl *This = impl_from_IDirectInputJoyConfig8( iface ); 1354 return IDirectInputAImpl_Release( &This->IDirectInput7A_iface ); 1355 } 1356 1357 static HRESULT WINAPI JoyConfig8Impl_Acquire(IDirectInputJoyConfig8 *iface) 1358 { 1359 FIXME( "(%p): stub!\n", iface ); 1360 return E_NOTIMPL; 1361 } 1362 1363 static HRESULT WINAPI JoyConfig8Impl_Unacquire(IDirectInputJoyConfig8 *iface) 1364 { 1365 FIXME( "(%p): stub!\n", iface ); 1366 return E_NOTIMPL; 1367 } 1368 1369 static HRESULT WINAPI JoyConfig8Impl_SetCooperativeLevel(IDirectInputJoyConfig8 *iface, HWND hwnd, DWORD flags) 1370 { 1371 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, hwnd, flags ); 1372 return E_NOTIMPL; 1373 } 1374 1375 static HRESULT WINAPI JoyConfig8Impl_SendNotify(IDirectInputJoyConfig8 *iface) 1376 { 1377 FIXME( "(%p): stub!\n", iface ); 1378 return E_NOTIMPL; 1379 } 1380 1381 static HRESULT WINAPI JoyConfig8Impl_EnumTypes(IDirectInputJoyConfig8 *iface, LPDIJOYTYPECALLBACK cb, void *ref) 1382 { 1383 FIXME( "(%p)->(%p, %p): stub!\n", iface, cb, ref ); 1384 return E_NOTIMPL; 1385 } 1386 1387 static HRESULT WINAPI JoyConfig8Impl_GetTypeInfo(IDirectInputJoyConfig8 *iface, LPCWSTR name, LPDIJOYTYPEINFO info, DWORD flags) 1388 { 1389 FIXME( "(%p)->(%s, %p, 0x%08x): stub!\n", iface, debugstr_w(name), info, flags ); 1390 return E_NOTIMPL; 1391 } 1392 1393 static HRESULT WINAPI JoyConfig8Impl_SetTypeInfo(IDirectInputJoyConfig8 *iface, LPCWSTR name, LPCDIJOYTYPEINFO info, DWORD flags, 1394 LPWSTR new_name) 1395 { 1396 FIXME( "(%p)->(%s, %p, 0x%08x, %s): stub!\n", iface, debugstr_w(name), info, flags, debugstr_w(new_name) ); 1397 return E_NOTIMPL; 1398 } 1399 1400 static HRESULT WINAPI JoyConfig8Impl_DeleteType(IDirectInputJoyConfig8 *iface, LPCWSTR name) 1401 { 1402 FIXME( "(%p)->(%s): stub!\n", iface, debugstr_w(name) ); 1403 return E_NOTIMPL; 1404 } 1405 1406 static HRESULT WINAPI JoyConfig8Impl_GetConfig(IDirectInputJoyConfig8 *iface, UINT id, LPDIJOYCONFIG info, DWORD flags) 1407 { 1408 IDirectInputImpl *di = impl_from_IDirectInputJoyConfig8(iface); 1409 UINT found = 0; 1410 int i, j; 1411 HRESULT r; 1412 1413 FIXME("(%p)->(%d, %p, 0x%08x): semi-stub!\n", iface, id, info, flags); 1414 1415 #define X(x) if (flags & x) FIXME("\tflags |= "#x"\n"); 1416 X(DIJC_GUIDINSTANCE) 1417 X(DIJC_REGHWCONFIGTYPE) 1418 X(DIJC_GAIN) 1419 X(DIJC_CALLOUT) 1420 #undef X 1421 1422 /* Enumerate all joysticks in order */ 1423 for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) 1424 { 1425 if (!dinput_devices[i]->enum_deviceA) continue; 1426 1427 for (j = 0, r = S_OK; SUCCEEDED(r); j++) 1428 { 1429 DIDEVICEINSTANCEA dev; 1430 dev.dwSize = sizeof(dev); 1431 if ((r = dinput_devices[i]->enum_deviceA(DI8DEVCLASS_GAMECTRL, 0, &dev, di->dwVersion, j)) == S_OK) 1432 { 1433 /* Only take into account the chosen id */ 1434 if (found == id) 1435 { 1436 if (flags & DIJC_GUIDINSTANCE) 1437 info->guidInstance = dev.guidInstance; 1438 1439 return DI_OK; 1440 } 1441 found += 1; 1442 } 1443 } 1444 } 1445 1446 return DIERR_NOMOREITEMS; 1447 } 1448 1449 static HRESULT WINAPI JoyConfig8Impl_SetConfig(IDirectInputJoyConfig8 *iface, UINT id, LPCDIJOYCONFIG info, DWORD flags) 1450 { 1451 FIXME( "(%p)->(%d, %p, 0x%08x): stub!\n", iface, id, info, flags ); 1452 return E_NOTIMPL; 1453 } 1454 1455 static HRESULT WINAPI JoyConfig8Impl_DeleteConfig(IDirectInputJoyConfig8 *iface, UINT id) 1456 { 1457 FIXME( "(%p)->(%d): stub!\n", iface, id ); 1458 return E_NOTIMPL; 1459 } 1460 1461 static HRESULT WINAPI JoyConfig8Impl_GetUserValues(IDirectInputJoyConfig8 *iface, LPDIJOYUSERVALUES info, DWORD flags) 1462 { 1463 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, info, flags ); 1464 return E_NOTIMPL; 1465 } 1466 1467 static HRESULT WINAPI JoyConfig8Impl_SetUserValues(IDirectInputJoyConfig8 *iface, LPCDIJOYUSERVALUES info, DWORD flags) 1468 { 1469 FIXME( "(%p)->(%p, 0x%08x): stub!\n", iface, info, flags ); 1470 return E_NOTIMPL; 1471 } 1472 1473 static HRESULT WINAPI JoyConfig8Impl_AddNewHardware(IDirectInputJoyConfig8 *iface, HWND hwnd, REFGUID guid) 1474 { 1475 FIXME( "(%p)->(%p, %s): stub!\n", iface, hwnd, debugstr_guid(guid) ); 1476 return E_NOTIMPL; 1477 } 1478 1479 static HRESULT WINAPI JoyConfig8Impl_OpenTypeKey(IDirectInputJoyConfig8 *iface, LPCWSTR name, DWORD security, PHKEY key) 1480 { 1481 FIXME( "(%p)->(%s, 0x%08x, %p): stub!\n", iface, debugstr_w(name), security, key ); 1482 return E_NOTIMPL; 1483 } 1484 1485 static HRESULT WINAPI JoyConfig8Impl_OpenAppStatusKey(IDirectInputJoyConfig8 *iface, PHKEY key) 1486 { 1487 FIXME( "(%p)->(%p): stub!\n", iface, key ); 1488 return E_NOTIMPL; 1489 } 1490 1491 static const IDirectInput7AVtbl ddi7avt = { 1492 IDirectInputAImpl_QueryInterface, 1493 IDirectInputAImpl_AddRef, 1494 IDirectInputAImpl_Release, 1495 IDirectInputAImpl_CreateDevice, 1496 IDirectInputAImpl_EnumDevices, 1497 IDirectInputAImpl_GetDeviceStatus, 1498 IDirectInputAImpl_RunControlPanel, 1499 IDirectInputAImpl_Initialize, 1500 IDirectInput2AImpl_FindDevice, 1501 IDirectInput7AImpl_CreateDeviceEx 1502 }; 1503 1504 static const IDirectInput7WVtbl ddi7wvt = { 1505 IDirectInputWImpl_QueryInterface, 1506 IDirectInputWImpl_AddRef, 1507 IDirectInputWImpl_Release, 1508 IDirectInputWImpl_CreateDevice, 1509 IDirectInputWImpl_EnumDevices, 1510 IDirectInputWImpl_GetDeviceStatus, 1511 IDirectInputWImpl_RunControlPanel, 1512 IDirectInputWImpl_Initialize, 1513 IDirectInput2WImpl_FindDevice, 1514 IDirectInput7WImpl_CreateDeviceEx 1515 }; 1516 1517 static const IDirectInput8AVtbl ddi8avt = { 1518 IDirectInput8AImpl_QueryInterface, 1519 IDirectInput8AImpl_AddRef, 1520 IDirectInput8AImpl_Release, 1521 IDirectInput8AImpl_CreateDevice, 1522 IDirectInput8AImpl_EnumDevices, 1523 IDirectInput8AImpl_GetDeviceStatus, 1524 IDirectInput8AImpl_RunControlPanel, 1525 IDirectInput8AImpl_Initialize, 1526 IDirectInput8AImpl_FindDevice, 1527 IDirectInput8AImpl_EnumDevicesBySemantics, 1528 IDirectInput8AImpl_ConfigureDevices 1529 }; 1530 1531 static const IDirectInput8WVtbl ddi8wvt = { 1532 IDirectInput8WImpl_QueryInterface, 1533 IDirectInput8WImpl_AddRef, 1534 IDirectInput8WImpl_Release, 1535 IDirectInput8WImpl_CreateDevice, 1536 IDirectInput8WImpl_EnumDevices, 1537 IDirectInput8WImpl_GetDeviceStatus, 1538 IDirectInput8WImpl_RunControlPanel, 1539 IDirectInput8WImpl_Initialize, 1540 IDirectInput8WImpl_FindDevice, 1541 IDirectInput8WImpl_EnumDevicesBySemantics, 1542 IDirectInput8WImpl_ConfigureDevices 1543 }; 1544 1545 static const IDirectInputJoyConfig8Vtbl JoyConfig8vt = 1546 { 1547 JoyConfig8Impl_QueryInterface, 1548 JoyConfig8Impl_AddRef, 1549 JoyConfig8Impl_Release, 1550 JoyConfig8Impl_Acquire, 1551 JoyConfig8Impl_Unacquire, 1552 JoyConfig8Impl_SetCooperativeLevel, 1553 JoyConfig8Impl_SendNotify, 1554 JoyConfig8Impl_EnumTypes, 1555 JoyConfig8Impl_GetTypeInfo, 1556 JoyConfig8Impl_SetTypeInfo, 1557 JoyConfig8Impl_DeleteType, 1558 JoyConfig8Impl_GetConfig, 1559 JoyConfig8Impl_SetConfig, 1560 JoyConfig8Impl_DeleteConfig, 1561 JoyConfig8Impl_GetUserValues, 1562 JoyConfig8Impl_SetUserValues, 1563 JoyConfig8Impl_AddNewHardware, 1564 JoyConfig8Impl_OpenTypeKey, 1565 JoyConfig8Impl_OpenAppStatusKey 1566 }; 1567 1568 /******************************************************************************* 1569 * DirectInput ClassFactory 1570 */ 1571 typedef struct 1572 { 1573 /* IUnknown fields */ 1574 IClassFactory IClassFactory_iface; 1575 LONG ref; 1576 } IClassFactoryImpl; 1577 1578 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) 1579 { 1580 return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); 1581 } 1582 1583 static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { 1584 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 1585 1586 FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); 1587 return E_NOINTERFACE; 1588 } 1589 1590 static ULONG WINAPI DICF_AddRef(LPCLASSFACTORY iface) { 1591 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 1592 return InterlockedIncrement(&(This->ref)); 1593 } 1594 1595 static ULONG WINAPI DICF_Release(LPCLASSFACTORY iface) { 1596 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 1597 /* static class, won't be freed */ 1598 return InterlockedDecrement(&(This->ref)); 1599 } 1600 1601 static HRESULT WINAPI DICF_CreateInstance( 1602 LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj 1603 ) { 1604 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 1605 1606 TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); 1607 if ( IsEqualGUID( &IID_IUnknown, riid ) || 1608 IsEqualGUID( &IID_IDirectInputA, riid ) || 1609 IsEqualGUID( &IID_IDirectInputW, riid ) || 1610 IsEqualGUID( &IID_IDirectInput2A, riid ) || 1611 IsEqualGUID( &IID_IDirectInput2W, riid ) || 1612 IsEqualGUID( &IID_IDirectInput7A, riid ) || 1613 IsEqualGUID( &IID_IDirectInput7W, riid ) || 1614 IsEqualGUID( &IID_IDirectInput8A, riid ) || 1615 IsEqualGUID( &IID_IDirectInput8W, riid ) ) 1616 { 1617 return create_directinput_instance(riid, ppobj, NULL); 1618 } 1619 1620 FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); 1621 return E_NOINTERFACE; 1622 } 1623 1624 static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { 1625 IClassFactoryImpl *This = impl_from_IClassFactory(iface); 1626 FIXME("(%p)->(%d),stub!\n",This,dolock); 1627 return S_OK; 1628 } 1629 1630 static const IClassFactoryVtbl DICF_Vtbl = { 1631 DICF_QueryInterface, 1632 DICF_AddRef, 1633 DICF_Release, 1634 DICF_CreateInstance, 1635 DICF_LockServer 1636 }; 1637 static IClassFactoryImpl DINPUT_CF = {{&DICF_Vtbl}, 1 }; 1638 1639 /*********************************************************************** 1640 * DllCanUnloadNow (DINPUT.@) 1641 */ 1642 HRESULT WINAPI DllCanUnloadNow(void) 1643 { 1644 return S_FALSE; 1645 } 1646 1647 /*********************************************************************** 1648 * DllGetClassObject (DINPUT.@) 1649 */ 1650 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) 1651 { 1652 TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); 1653 if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { 1654 *ppv = &DINPUT_CF; 1655 IClassFactory_AddRef((IClassFactory*)*ppv); 1656 return S_OK; 1657 } 1658 1659 FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); 1660 return CLASS_E_CLASSNOTAVAILABLE; 1661 } 1662 1663 /*********************************************************************** 1664 * DllRegisterServer (DINPUT.@) 1665 */ 1666 HRESULT WINAPI DllRegisterServer(void) 1667 { 1668 return __wine_register_resources( DINPUT_instance ); 1669 } 1670 1671 /*********************************************************************** 1672 * DllUnregisterServer (DINPUT.@) 1673 */ 1674 HRESULT WINAPI DllUnregisterServer(void) 1675 { 1676 return __wine_unregister_resources( DINPUT_instance ); 1677 } 1678 1679 /****************************************************************************** 1680 * DInput hook thread 1681 */ 1682 1683 static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) 1684 { 1685 IDirectInputImpl *dinput; 1686 int skip = 0; 1687 1688 if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam ); 1689 1690 EnterCriticalSection( &dinput_hook_crit ); 1691 LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry ) 1692 { 1693 IDirectInputDeviceImpl *dev; 1694 1695 EnterCriticalSection( &dinput->crit ); 1696 LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry ) 1697 if (dev->acquired && dev->event_proc) 1698 { 1699 TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam); 1700 skip |= dev->event_proc( &dev->IDirectInputDevice8A_iface, wparam, lparam ); 1701 } 1702 LeaveCriticalSection( &dinput->crit ); 1703 } 1704 LeaveCriticalSection( &dinput_hook_crit ); 1705 1706 return skip ? 1 : CallNextHookEx( 0, code, wparam, lparam ); 1707 } 1708 1709 static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam ) 1710 { 1711 CWPSTRUCT *msg = (CWPSTRUCT *)lparam; 1712 IDirectInputImpl *dinput; 1713 HWND foreground; 1714 1715 if (code != HC_ACTION || (msg->message != WM_KILLFOCUS && 1716 msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE)) 1717 return CallNextHookEx( 0, code, wparam, lparam ); 1718 1719 foreground = GetForegroundWindow(); 1720 1721 EnterCriticalSection( &dinput_hook_crit ); 1722 1723 LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry ) 1724 { 1725 IDirectInputDeviceImpl *dev; 1726 1727 EnterCriticalSection( &dinput->crit ); 1728 LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry ) 1729 { 1730 if (!dev->acquired) continue; 1731 1732 if (msg->hwnd == dev->win && msg->hwnd != foreground) 1733 { 1734 TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev ); 1735 IDirectInputDevice_Unacquire( &dev->IDirectInputDevice8A_iface ); 1736 } 1737 } 1738 LeaveCriticalSection( &dinput->crit ); 1739 } 1740 LeaveCriticalSection( &dinput_hook_crit ); 1741 1742 return CallNextHookEx( 0, code, wparam, lparam ); 1743 } 1744 1745 static DWORD WINAPI hook_thread_proc(void *param) 1746 { 1747 static HHOOK kbd_hook, mouse_hook; 1748 MSG msg; 1749 1750 /* Force creation of the message queue */ 1751 PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); 1752 SetEvent(param); 1753 1754 while (GetMessageW( &msg, 0, 0, 0 )) 1755 { 1756 UINT kbd_cnt = 0, mice_cnt = 0; 1757 1758 if (msg.message == WM_USER+0x10) 1759 { 1760 IDirectInputImpl *dinput; 1761 1762 TRACE( "Processing hook change notification lp:%ld\n", msg.lParam ); 1763 1764 if (!msg.wParam && !msg.lParam) 1765 { 1766 if (kbd_hook) UnhookWindowsHookEx( kbd_hook ); 1767 if (mouse_hook) UnhookWindowsHookEx( mouse_hook ); 1768 kbd_hook = mouse_hook = NULL; 1769 break; 1770 } 1771 1772 EnterCriticalSection( &dinput_hook_crit ); 1773 1774 /* Count acquired keyboards and mice*/ 1775 LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry ) 1776 { 1777 IDirectInputDeviceImpl *dev; 1778 1779 EnterCriticalSection( &dinput->crit ); 1780 LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDeviceImpl, entry ) 1781 { 1782 if (!dev->acquired || !dev->event_proc) continue; 1783 1784 if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard )) 1785 kbd_cnt++; 1786 else 1787 if (IsEqualGUID( &dev->guid, &GUID_SysMouse )) 1788 mice_cnt++; 1789 } 1790 LeaveCriticalSection( &dinput->crit ); 1791 } 1792 LeaveCriticalSection( &dinput_hook_crit ); 1793 1794 if (kbd_cnt && !kbd_hook) 1795 kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 ); 1796 else if (!kbd_cnt && kbd_hook) 1797 { 1798 UnhookWindowsHookEx( kbd_hook ); 1799 kbd_hook = NULL; 1800 } 1801 1802 if (mice_cnt && !mouse_hook) 1803 mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 ); 1804 else if (!mice_cnt && mouse_hook) 1805 { 1806 UnhookWindowsHookEx( mouse_hook ); 1807 mouse_hook = NULL; 1808 } 1809 } 1810 TranslateMessage(&msg); 1811 DispatchMessageW(&msg); 1812 } 1813 1814 FreeLibraryAndExitThread(DINPUT_instance, 0); 1815 } 1816 1817 static DWORD hook_thread_id; 1818 static HANDLE hook_thread_event; 1819 1820 static CRITICAL_SECTION_DEBUG dinput_critsect_debug = 1821 { 1822 0, 0, &dinput_hook_crit, 1823 { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList }, 1824 0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") } 1825 }; 1826 static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 }; 1827 1828 static BOOL check_hook_thread(void) 1829 { 1830 static HANDLE hook_thread; 1831 HMODULE module; 1832 1833 EnterCriticalSection(&dinput_hook_crit); 1834 1835 TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list)); 1836 if (!list_empty(&direct_input_list) && !hook_thread) 1837 { 1838 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)DINPUT_instance, &module); 1839 hook_thread_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1840 hook_thread = CreateThread(NULL, 0, hook_thread_proc, hook_thread_event, 0, &hook_thread_id); 1841 } 1842 else if (list_empty(&direct_input_list) && hook_thread) 1843 { 1844 DWORD tid = hook_thread_id; 1845 1846 if (hook_thread_event) /* if thread is not started yet */ 1847 { 1848 WaitForSingleObject(hook_thread_event, INFINITE); 1849 CloseHandle(hook_thread_event); 1850 hook_thread_event = NULL; 1851 } 1852 1853 hook_thread_id = 0; 1854 PostThreadMessageW(tid, WM_USER+0x10, 0, 0); 1855 CloseHandle(hook_thread); 1856 hook_thread = NULL; 1857 } 1858 1859 LeaveCriticalSection(&dinput_hook_crit); 1860 return hook_thread_id != 0; 1861 } 1862 1863 void check_dinput_hooks(LPDIRECTINPUTDEVICE8W iface, BOOL acquired) 1864 { 1865 static HHOOK callwndproc_hook; 1866 static ULONG foreground_cnt; 1867 IDirectInputDeviceImpl *dev = impl_from_IDirectInputDevice8W(iface); 1868 1869 EnterCriticalSection(&dinput_hook_crit); 1870 1871 if (dev->dwCoopLevel & DISCL_FOREGROUND) 1872 { 1873 if (acquired) 1874 foreground_cnt++; 1875 else 1876 foreground_cnt--; 1877 } 1878 1879 if (foreground_cnt && !callwndproc_hook) 1880 callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc, 1881 DINPUT_instance, GetCurrentThreadId() ); 1882 else if (!foreground_cnt && callwndproc_hook) 1883 { 1884 UnhookWindowsHookEx( callwndproc_hook ); 1885 callwndproc_hook = NULL; 1886 } 1887 1888 if (hook_thread_event) /* if thread is not started yet */ 1889 { 1890 WaitForSingleObject(hook_thread_event, INFINITE); 1891 CloseHandle(hook_thread_event); 1892 hook_thread_event = NULL; 1893 } 1894 1895 PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 ); 1896 1897 LeaveCriticalSection(&dinput_hook_crit); 1898 } 1899 1900 void check_dinput_events(void) 1901 { 1902 /* Windows does not do that, but our current implementation of winex11 1903 * requires periodic event polling to forward events to the wineserver. 1904 * 1905 * We have to call this function from multiple places, because: 1906 * - some games do not explicitly poll for mouse events 1907 * (for example Culpa Innata) 1908 * - some games only poll the device, and neither keyboard nor mouse 1909 * (for example Civilization: Call to Power 2) 1910 */ 1911 #ifndef __REACTOS__ 1912 MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0); 1913 #endif 1914 } 1915 1916 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) 1917 { 1918 switch(reason) 1919 { 1920 case DLL_PROCESS_ATTACH: 1921 DisableThreadLibraryCalls(inst); 1922 DINPUT_instance = inst; 1923 break; 1924 case DLL_PROCESS_DETACH: 1925 if (reserved) break; 1926 DeleteCriticalSection(&dinput_hook_crit); 1927 break; 1928 } 1929 return TRUE; 1930 } 1931