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