1 /* 2 * Copyright (c) 2011 Andrew Nguyen 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #define DIRECTINPUT_VERSION 0x0800 20 21 #define COBJMACROS 22 #include <initguid.h> 23 #include <windows.h> 24 #include <dinput.h> 25 #include <dinputd.h> 26 27 #include "wine/test.h" 28 29 HINSTANCE hInstance; 30 31 static BOOL CALLBACK dummy_callback(const DIDEVICEINSTANCEA *instance, void *context) 32 { 33 ok(0, "Callback was invoked with parameters (%p, %p)\n", instance, context); 34 return DIENUM_STOP; 35 } 36 37 static void test_preinitialization(void) 38 { 39 static const struct 40 { 41 REFGUID rguid; 42 BOOL pdev; 43 HRESULT expected_hr; 44 } create_device_tests[] = 45 { 46 {NULL, FALSE, E_POINTER}, 47 {NULL, TRUE, E_POINTER}, 48 {&GUID_Unknown, FALSE, E_POINTER}, 49 {&GUID_Unknown, TRUE, DIERR_NOTINITIALIZED}, 50 {&GUID_SysMouse, FALSE, E_POINTER}, 51 {&GUID_SysMouse, TRUE, DIERR_NOTINITIALIZED}, 52 }; 53 54 static const struct 55 { 56 DWORD dwDevType; 57 LPDIENUMDEVICESCALLBACKA lpCallback; 58 DWORD dwFlags; 59 HRESULT expected_hr; 60 int todo; 61 } enum_devices_tests[] = 62 { 63 {0, NULL, 0, DIERR_INVALIDPARAM}, 64 {0, NULL, ~0u, DIERR_INVALIDPARAM}, 65 {0, dummy_callback, 0, DIERR_NOTINITIALIZED}, 66 {0, dummy_callback, ~0u, DIERR_INVALIDPARAM}, 67 {0xdeadbeef, NULL, 0, DIERR_INVALIDPARAM}, 68 {0xdeadbeef, NULL, ~0u, DIERR_INVALIDPARAM}, 69 {0xdeadbeef, dummy_callback, 0, DIERR_INVALIDPARAM}, 70 {0xdeadbeef, dummy_callback, ~0u, DIERR_INVALIDPARAM}, 71 }; 72 73 IDirectInput8A *pDI; 74 HRESULT hr; 75 int i; 76 IDirectInputDevice8A *pDID; 77 78 hr = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (void **)&pDI); 79 if (FAILED(hr)) 80 { 81 skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr); 82 return; 83 } 84 85 for (i = 0; i < ARRAY_SIZE(create_device_tests); i++) 86 { 87 if (create_device_tests[i].pdev) pDID = (void *)0xdeadbeef; 88 hr = IDirectInput8_CreateDevice(pDI, create_device_tests[i].rguid, 89 create_device_tests[i].pdev ? &pDID : NULL, 90 NULL); 91 ok(hr == create_device_tests[i].expected_hr, "[%d] IDirectInput8_CreateDevice returned 0x%08x\n", i, hr); 92 if (create_device_tests[i].pdev) 93 ok(pDID == NULL, "[%d] Output interface pointer is %p\n", i, pDID); 94 } 95 96 for (i = 0; i < ARRAY_SIZE(enum_devices_tests); i++) 97 { 98 hr = IDirectInput8_EnumDevices(pDI, enum_devices_tests[i].dwDevType, 99 enum_devices_tests[i].lpCallback, 100 NULL, 101 enum_devices_tests[i].dwFlags); 102 todo_wine_if(enum_devices_tests[i].todo) 103 ok(hr == enum_devices_tests[i].expected_hr, "[%d] IDirectInput8_EnumDevice returned 0x%08x\n", i, hr); 104 } 105 106 hr = IDirectInput8_GetDeviceStatus(pDI, NULL); 107 ok(hr == E_POINTER, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr); 108 109 hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_Unknown); 110 ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr); 111 112 hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_SysMouse); 113 ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr); 114 115 hr = IDirectInput8_RunControlPanel(pDI, NULL, 0); 116 ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 117 118 hr = IDirectInput8_RunControlPanel(pDI, NULL, ~0u); 119 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 120 121 hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, 0); 122 ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 123 124 hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, ~0u); 125 ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 126 127 IDirectInput8_Release(pDI); 128 } 129 130 static void test_DirectInput8Create(void) 131 { 132 static const struct 133 { 134 BOOL hinst; 135 DWORD dwVersion; 136 REFIID riid; 137 BOOL ppdi; 138 HRESULT expected_hr; 139 } invalid_param_list[] = 140 { 141 {FALSE, 0, &IID_IDirectInputA, FALSE, E_POINTER}, 142 {FALSE, 0, &IID_IDirectInputA, TRUE, DIERR_NOINTERFACE}, 143 {FALSE, 0, &IID_IDirectInput8A, FALSE, E_POINTER}, 144 {FALSE, 0, &IID_IDirectInput8A, TRUE, DIERR_INVALIDPARAM}, 145 {FALSE, DIRECTINPUT_VERSION, &IID_IDirectInputA, FALSE, E_POINTER}, 146 {FALSE, DIRECTINPUT_VERSION, &IID_IDirectInputA, TRUE, DIERR_NOINTERFACE}, 147 {FALSE, DIRECTINPUT_VERSION, &IID_IDirectInput8A, FALSE, E_POINTER}, 148 {FALSE, DIRECTINPUT_VERSION, &IID_IDirectInput8A, TRUE, DIERR_INVALIDPARAM}, 149 {FALSE, DIRECTINPUT_VERSION - 1, &IID_IDirectInputA, FALSE, E_POINTER}, 150 {FALSE, DIRECTINPUT_VERSION - 1, &IID_IDirectInputA, TRUE, DIERR_NOINTERFACE}, 151 {FALSE, DIRECTINPUT_VERSION - 1, &IID_IDirectInput8A, FALSE, E_POINTER}, 152 {FALSE, DIRECTINPUT_VERSION - 1, &IID_IDirectInput8A, TRUE, DIERR_INVALIDPARAM}, 153 {FALSE, DIRECTINPUT_VERSION + 1, &IID_IDirectInputA, FALSE, E_POINTER}, 154 {FALSE, DIRECTINPUT_VERSION + 1, &IID_IDirectInputA, TRUE, DIERR_NOINTERFACE}, 155 {FALSE, DIRECTINPUT_VERSION + 1, &IID_IDirectInput8A, FALSE, E_POINTER}, 156 {FALSE, DIRECTINPUT_VERSION + 1, &IID_IDirectInput8A, TRUE, DIERR_INVALIDPARAM}, 157 {TRUE, 0, &IID_IDirectInputA, FALSE, E_POINTER}, 158 {TRUE, 0, &IID_IDirectInputA, TRUE, DIERR_NOINTERFACE}, 159 {TRUE, 0, &IID_IDirectInput8A, FALSE, E_POINTER}, 160 {TRUE, 0, &IID_IDirectInput8A, TRUE, DIERR_NOTINITIALIZED}, 161 {TRUE, DIRECTINPUT_VERSION, &IID_IDirectInputA, FALSE, E_POINTER}, 162 {TRUE, DIRECTINPUT_VERSION, &IID_IDirectInputA, TRUE, DIERR_NOINTERFACE}, 163 {TRUE, DIRECTINPUT_VERSION, &IID_IDirectInput8A, FALSE, E_POINTER}, 164 {TRUE, DIRECTINPUT_VERSION - 1, &IID_IDirectInputA, FALSE, E_POINTER}, 165 {TRUE, DIRECTINPUT_VERSION - 1, &IID_IDirectInputA, TRUE, DIERR_NOINTERFACE}, 166 {TRUE, DIRECTINPUT_VERSION - 1, &IID_IDirectInput8A, FALSE, E_POINTER}, 167 {TRUE, DIRECTINPUT_VERSION - 1, &IID_IDirectInput8A, TRUE, DIERR_BETADIRECTINPUTVERSION}, 168 {TRUE, DIRECTINPUT_VERSION + 1, &IID_IDirectInputA, FALSE, E_POINTER}, 169 {TRUE, DIRECTINPUT_VERSION + 1, &IID_IDirectInputA, TRUE, DIERR_NOINTERFACE}, 170 {TRUE, DIRECTINPUT_VERSION + 1, &IID_IDirectInput8A, FALSE, E_POINTER}, 171 {TRUE, DIRECTINPUT_VERSION + 1, &IID_IDirectInput8A, TRUE, DIERR_OLDDIRECTINPUTVERSION}, 172 }; 173 174 static REFIID no_interface_list[] = {&IID_IDirectInputA, &IID_IDirectInputW, 175 &IID_IDirectInput2A, &IID_IDirectInput2W, 176 &IID_IDirectInput7A, &IID_IDirectInput7W, 177 &IID_IDirectInputDeviceA, &IID_IDirectInputDeviceW, 178 &IID_IDirectInputDevice2A, &IID_IDirectInputDevice2W, 179 &IID_IDirectInputDevice7A, &IID_IDirectInputDevice7W, 180 &IID_IDirectInputDevice8A, &IID_IDirectInputDevice8W, 181 &IID_IDirectInputEffect}; 182 183 static REFIID iid_list[] = {&IID_IUnknown, &IID_IDirectInput8A, &IID_IDirectInput8W}; 184 185 int i; 186 IUnknown *pUnk; 187 HRESULT hr; 188 189 for (i = 0; i < ARRAY_SIZE(invalid_param_list); i++) 190 { 191 if (invalid_param_list[i].ppdi) pUnk = (void *)0xdeadbeef; 192 hr = DirectInput8Create(invalid_param_list[i].hinst ? hInstance : NULL, 193 invalid_param_list[i].dwVersion, 194 invalid_param_list[i].riid, 195 invalid_param_list[i].ppdi ? (void **)&pUnk : NULL, 196 NULL); 197 ok(hr == invalid_param_list[i].expected_hr, "[%d] DirectInput8Create returned 0x%08x\n", i, hr); 198 if (invalid_param_list[i].ppdi) 199 ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk); 200 } 201 202 for (i = 0; i < ARRAY_SIZE(no_interface_list); i++) 203 { 204 pUnk = (void *)0xdeadbeef; 205 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, no_interface_list[i], (void **)&pUnk, NULL); 206 ok(hr == DIERR_NOINTERFACE, "[%d] DirectInput8Create returned 0x%08x\n", i, hr); 207 ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk); 208 } 209 210 for (i = 0; i < ARRAY_SIZE(iid_list); i++) 211 { 212 pUnk = NULL; 213 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, iid_list[i], (void **)&pUnk, NULL); 214 ok(hr == DI_OK, "[%d] DirectInput8Create returned 0x%08x\n", i, hr); 215 ok(pUnk != NULL, "[%d] Output interface pointer is NULL\n", i); 216 if (pUnk) 217 IUnknown_Release(pUnk); 218 } 219 } 220 221 static void test_QueryInterface(void) 222 { 223 static REFIID iid_list[] = {&IID_IUnknown, &IID_IDirectInput8A, &IID_IDirectInput8W, &IID_IDirectInputJoyConfig8}; 224 225 static REFIID no_interface_list[] = 226 { 227 &IID_IDirectInputA, 228 &IID_IDirectInputW, 229 &IID_IDirectInput2A, 230 &IID_IDirectInput2W, 231 &IID_IDirectInput7A, 232 &IID_IDirectInput7W, 233 &IID_IDirectInputDeviceA, 234 &IID_IDirectInputDeviceW, 235 &IID_IDirectInputDevice2A, 236 &IID_IDirectInputDevice2W, 237 &IID_IDirectInputDevice7A, 238 &IID_IDirectInputDevice7W, 239 &IID_IDirectInputDevice8A, 240 &IID_IDirectInputDevice8W, 241 &IID_IDirectInputEffect, 242 }; 243 244 IDirectInput8A *pDI; 245 HRESULT hr; 246 IUnknown *pUnk; 247 int i; 248 249 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL); 250 if (FAILED(hr)) 251 { 252 win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr); 253 return; 254 } 255 256 hr = IDirectInput8_QueryInterface(pDI, NULL, NULL); 257 ok(hr == E_POINTER, "IDirectInput8_QueryInterface returned 0x%08x\n", hr); 258 259 pUnk = (void *)0xdeadbeef; 260 hr = IDirectInput8_QueryInterface(pDI, NULL, (void **)&pUnk); 261 ok(hr == E_POINTER, "IDirectInput8_QueryInterface returned 0x%08x\n", hr); 262 ok(pUnk == (void *)0xdeadbeef, "Output interface pointer is %p\n", pUnk); 263 264 hr = IDirectInput8_QueryInterface(pDI, &IID_IUnknown, NULL); 265 ok(hr == E_POINTER, "IDirectInput8_QueryInterface returned 0x%08x\n", hr); 266 267 for (i = 0; i < ARRAY_SIZE(iid_list); i++) 268 { 269 pUnk = NULL; 270 hr = IDirectInput8_QueryInterface(pDI, iid_list[i], (void **)&pUnk); 271 ok(hr == S_OK, "[%d] IDirectInput8_QueryInterface returned 0x%08x\n", i, hr); 272 ok(pUnk != NULL, "[%d] Output interface pointer is NULL\n", i); 273 if (pUnk) 274 { 275 int j; 276 for (j = 0; j < ARRAY_SIZE(iid_list); j++) 277 { 278 IUnknown *pUnk1 = NULL; 279 hr = IDirectInput8_QueryInterface(pUnk, iid_list[j], (void **)&pUnk1); 280 ok(hr == S_OK, "[%d] IDirectInput8_QueryInterface(pUnk) returned 0x%08x\n", j, hr); 281 ok(pUnk1 != NULL, "[%d] Output interface pointer is NULL\n", i); 282 if (pUnk1) IUnknown_Release(pUnk1); 283 } 284 IUnknown_Release(pUnk); 285 } 286 } 287 288 for (i = 0; i < ARRAY_SIZE(no_interface_list); i++) 289 { 290 pUnk = (void *)0xdeadbeef; 291 hr = IDirectInput8_QueryInterface(pDI, no_interface_list[i], (void **)&pUnk); 292 293 ok(hr == E_NOINTERFACE, "[%d] IDirectInput8_QueryInterface returned 0x%08x\n", i, hr); 294 ok(pUnk == NULL, "[%d] Output interface pointer is %p\n", i, pUnk); 295 } 296 297 IDirectInput8_Release(pDI); 298 } 299 300 static void test_CreateDevice(void) 301 { 302 IDirectInput8A *pDI; 303 HRESULT hr; 304 IDirectInputDevice8A *pDID; 305 306 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL); 307 if (FAILED(hr)) 308 { 309 win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr); 310 return; 311 } 312 313 hr = IDirectInput8_CreateDevice(pDI, NULL, NULL, NULL); 314 ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr); 315 316 pDID = (void *)0xdeadbeef; 317 hr = IDirectInput8_CreateDevice(pDI, NULL, &pDID, NULL); 318 ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr); 319 ok(pDID == NULL, "Output interface pointer is %p\n", pDID); 320 321 hr = IDirectInput8_CreateDevice(pDI, &GUID_Unknown, NULL, NULL); 322 ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr); 323 324 pDID = (void *)0xdeadbeef; 325 hr = IDirectInput8_CreateDevice(pDI, &GUID_Unknown, &pDID, NULL); 326 ok(hr == DIERR_DEVICENOTREG, "IDirectInput8_CreateDevice returned 0x%08x\n", hr); 327 ok(pDID == NULL, "Output interface pointer is %p\n", pDID); 328 329 hr = IDirectInput8_CreateDevice(pDI, &GUID_SysMouse, NULL, NULL); 330 ok(hr == E_POINTER, "IDirectInput8_CreateDevice returned 0x%08x\n", hr); 331 332 hr = IDirectInput8_CreateDevice(pDI, &GUID_SysMouse, &pDID, NULL); 333 ok(hr == DI_OK, "IDirectInput8_CreateDevice returned 0x%08x\n", hr); 334 335 IDirectInputDevice_Release(pDID); 336 IDirectInput8_Release(pDI); 337 } 338 339 struct enum_devices_test 340 { 341 unsigned int device_count; 342 BOOL return_value; 343 }; 344 345 static BOOL CALLBACK enum_devices_callback(const DIDEVICEINSTANCEA *instance, void *context) 346 { 347 struct enum_devices_test *enum_test = context; 348 349 trace("---- Device Information ----\n" 350 "Product Name : %s\n" 351 "Instance Name : %s\n" 352 "devType : 0x%08x\n" 353 "GUID Product : %s\n" 354 "GUID Instance : %s\n" 355 "HID Page : 0x%04x\n" 356 "HID Usage : 0x%04x\n", 357 instance->tszProductName, 358 instance->tszInstanceName, 359 instance->dwDevType, 360 wine_dbgstr_guid(&instance->guidProduct), 361 wine_dbgstr_guid(&instance->guidInstance), 362 instance->wUsagePage, 363 instance->wUsage); 364 365 if ((instance->dwDevType & 0xff) == DI8DEVTYPE_KEYBOARD || 366 (instance->dwDevType & 0xff) == DI8DEVTYPE_MOUSE) { 367 const char *device = ((instance->dwDevType & 0xff) == 368 DI8DEVTYPE_KEYBOARD) ? "Keyboard" : "Mouse"; 369 ok(IsEqualGUID(&instance->guidInstance, &instance->guidProduct), 370 "%s guidInstance (%s) does not match guidProduct (%s)\n", 371 device, wine_dbgstr_guid(&instance->guidInstance), 372 wine_dbgstr_guid(&instance->guidProduct)); 373 } 374 375 enum_test->device_count++; 376 return enum_test->return_value; 377 } 378 379 static void test_EnumDevices(void) 380 { 381 IDirectInput8A *pDI; 382 HRESULT hr; 383 struct enum_devices_test enum_test, enum_test_return; 384 385 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL); 386 if (FAILED(hr)) 387 { 388 win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr); 389 return; 390 } 391 392 hr = IDirectInput8_EnumDevices(pDI, 0, NULL, NULL, 0); 393 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 394 395 hr = IDirectInput8_EnumDevices(pDI, 0, NULL, NULL, ~0u); 396 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 397 398 /* Test crashes on Wine. */ 399 if (0) 400 { 401 hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, NULL, ~0u); 402 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 403 } 404 405 hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, NULL, NULL, 0); 406 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 407 408 hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, NULL, NULL, ~0u); 409 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 410 411 hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, enum_devices_callback, NULL, 0); 412 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 413 414 hr = IDirectInput8_EnumDevices(pDI, 0xdeadbeef, enum_devices_callback, NULL, ~0u); 415 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 416 417 enum_test.device_count = 0; 418 enum_test.return_value = DIENUM_CONTINUE; 419 hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test, 0); 420 ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 421 ok(enum_test.device_count != 0, "Device count is %u\n", enum_test.device_count); 422 423 /* Enumeration only stops with an explicit DIENUM_STOP. */ 424 enum_test_return.device_count = 0; 425 enum_test_return.return_value = 42; 426 hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test_return, 0); 427 ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 428 ok(enum_test_return.device_count == enum_test.device_count, 429 "Device count is %u vs. %u\n", enum_test_return.device_count, enum_test.device_count); 430 431 enum_test.device_count = 0; 432 enum_test.return_value = DIENUM_STOP; 433 hr = IDirectInput8_EnumDevices(pDI, 0, enum_devices_callback, &enum_test, 0); 434 ok(hr == DI_OK, "IDirectInput8_EnumDevices returned 0x%08x\n", hr); 435 ok(enum_test.device_count == 1, "Device count is %u\n", enum_test.device_count); 436 437 IDirectInput8_Release(pDI); 438 } 439 440 struct enum_semantics_test 441 { 442 unsigned int device_count; 443 DWORD first_remaining; 444 BOOL mouse; 445 BOOL keyboard; 446 DIACTIONFORMATA *lpdiaf; 447 const char* username; 448 }; 449 450 static DIACTIONA actionMapping[]= 451 { 452 /* axis */ 453 { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */, 0, { "Steer.\0" } }, 454 /* button */ 455 { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */, 0, { "Upshift.\0" } }, 456 /* keyboard key */ 457 { 2, DIKEYBOARD_SPACE, 0, { "Missile.\0" } }, 458 /* mouse button */ 459 { 3, DIMOUSE_BUTTON0, 0, { "Select\0" } }, 460 /* mouse axis */ 461 { 4, DIMOUSE_YAXIS, 0, { "Y Axis\0" } } 462 }; 463 /* By placing the memory pointed to by lptszActionName right before memory with PAGE_NOACCESS 464 * one can find out that the regular ansi string termination is not respected by EnumDevicesBySemantics. 465 * Adding a double termination, making it a valid wide string termination, made the test succeed. 466 * Therefore it looks like ansi version of EnumDevicesBySemantics forwards the string to 467 * the wide variant without conversation. */ 468 469 static BOOL CALLBACK enum_semantics_callback(const DIDEVICEINSTANCEA *lpddi, IDirectInputDevice8A *lpdid, DWORD dwFlags, DWORD dwRemaining, void *context) 470 { 471 struct enum_semantics_test *data = context; 472 473 if (context == NULL) return DIENUM_STOP; 474 475 if (!data->device_count) { 476 data->first_remaining = dwRemaining; 477 } 478 ok (dwRemaining == data->first_remaining - data->device_count, 479 "enum semantics remaining devices is wrong, expected %d, had %d\n", 480 data->first_remaining - data->device_count, dwRemaining); 481 data->device_count++; 482 483 if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysKeyboard)) data->keyboard = TRUE; 484 485 if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysMouse)) data->mouse = TRUE; 486 487 return DIENUM_CONTINUE; 488 } 489 490 static BOOL CALLBACK set_action_map_callback(const DIDEVICEINSTANCEA *lpddi, IDirectInputDevice8A *lpdid, DWORD dwFlags, DWORD dwRemaining, void *context) 491 { 492 HRESULT hr; 493 struct enum_semantics_test *data = context; 494 495 /* Building and setting an action map */ 496 /* It should not use any pre-stored mappings so we use DIDBAM_INITIALIZE */ 497 hr = IDirectInputDevice8_BuildActionMap(lpdid, data->lpdiaf, NULL, DIDBAM_INITIALIZE); 498 ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr); 499 500 hr = IDirectInputDevice8_SetActionMap(lpdid, data->lpdiaf, data->username, 0); 501 ok (SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr); 502 503 return DIENUM_CONTINUE; 504 } 505 506 static void test_EnumDevicesBySemantics(void) 507 { 508 IDirectInput8A *pDI; 509 HRESULT hr; 510 DIACTIONFORMATA diaf; 511 const GUID ACTION_MAPPING_GUID = { 0x1, 0x2, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } }; 512 struct enum_semantics_test data = { 0, 0, FALSE, FALSE, &diaf, NULL }; 513 int device_total = 0; 514 515 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL); 516 if (FAILED(hr)) 517 { 518 win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr); 519 return; 520 } 521 522 memset (&diaf, 0, sizeof(diaf)); 523 diaf.dwSize = sizeof(diaf); 524 diaf.dwActionSize = sizeof(DIACTIONA); 525 diaf.dwNumActions = ARRAY_SIZE(actionMapping); 526 diaf.dwDataSize = 4 * diaf.dwNumActions; 527 diaf.rgoAction = actionMapping; 528 diaf.guidActionMap = ACTION_MAPPING_GUID; 529 diaf.dwGenre = 0x01000000; /* DIVIRTUAL_DRIVING_RACE */ 530 diaf.dwBufferSize = 32; 531 532 /* Test enumerating all attached and installed devices */ 533 data.keyboard = FALSE; 534 data.mouse = FALSE; 535 data.device_count = 0; 536 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_ATTACHEDONLY); 537 ok (data.device_count > 0, "EnumDevicesBySemantics did not call the callback hr=%08x\n", hr); 538 ok (data.keyboard, "EnumDevicesBySemantics should enumerate the keyboard\n"); 539 ok (data.mouse, "EnumDevicesBySemantics should enumerate the mouse\n"); 540 541 /* Enumerate Force feedback devices. We should get no mouse nor keyboard */ 542 data.keyboard = FALSE; 543 data.mouse = FALSE; 544 data.device_count = 0; 545 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_FORCEFEEDBACK); 546 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr); 547 ok (!data.keyboard, "Keyboard should not be enumerated when asking for forcefeedback\n"); 548 ok (!data.mouse, "Mouse should not be enumerated when asking for forcefeedback\n"); 549 550 /* Enumerate available devices. That is devices not owned by any user. 551 Before setting the action map for all devices we still have them available. */ 552 data.device_count = 0; 553 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_AVAILABLEDEVICES); 554 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr); 555 ok (data.device_count > 0, "There should be devices available before action mapping available=%d\n", data.device_count); 556 557 /* Keep the device total */ 558 device_total = data.device_count; 559 560 /* There should be no devices for any user. No device should be enumerated with DIEDBSFL_THISUSER. 561 MSDN defines that all unowned devices are also enumerated but this doesn't seem to be happening. */ 562 data.device_count = 0; 563 hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Sh4d0w M4g3", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER); 564 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr); 565 ok (data.device_count == 0, "No devices should be assigned for this user assigned=%d\n", data.device_count); 566 567 /* This enumeration builds and sets the action map for all devices with a NULL username */ 568 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, set_action_map_callback, &data, DIEDBSFL_ATTACHEDONLY); 569 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr); 570 571 /* After a successful action mapping we should have no devices available */ 572 data.device_count = 0; 573 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_AVAILABLEDEVICES); 574 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr); 575 ok (data.device_count == 0, "No device should be available after action mapping available=%d\n", data.device_count); 576 577 /* Now we'll give all the devices to a specific user */ 578 data.username = "Sh4d0w M4g3"; 579 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, set_action_map_callback, &data, DIEDBSFL_ATTACHEDONLY); 580 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr); 581 582 /* Testing with the default user, DIEDBSFL_THISUSER has no effect */ 583 data.device_count = 0; 584 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER); 585 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr); 586 ok (data.device_count == device_total, "THISUSER has no effect with NULL username owned=%d, expected=%d\n", data.device_count, device_total); 587 588 /* Using an empty user string is the same as passing NULL, DIEDBSFL_THISUSER has no effect */ 589 data.device_count = 0; 590 hr = IDirectInput8_EnumDevicesBySemantics(pDI, "", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER); 591 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr); 592 ok (data.device_count == device_total, "THISUSER has no effect with \"\" as username owned=%d, expected=%d\n", data.device_count, device_total); 593 594 /* Testing with a user with no ownership of the devices */ 595 data.device_count = 0; 596 hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Ninja Brian", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER); 597 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr); 598 ok (data.device_count == 0, "This user should own no devices owned=%d\n", data.device_count); 599 600 /* Sh4d0w M4g3 has ownership of all devices */ 601 data.device_count = 0; 602 hr = IDirectInput8_EnumDevicesBySemantics(pDI, "Sh4d0w M4g3", &diaf, enum_semantics_callback, &data, DIEDBSFL_THISUSER); 603 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed hr=%08x\n", hr); 604 ok (data.device_count == device_total, "This user should own %d devices owned=%d\n", device_total, data.device_count); 605 606 /* The call fails with a zeroed GUID */ 607 memset(&diaf.guidActionMap, 0, sizeof(GUID)); 608 data.device_count = 0; 609 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &diaf, enum_semantics_callback, NULL, 0); 610 todo_wine ok(FAILED(hr), "EnumDevicesBySemantics succeeded with invalid GUID hr=%08x\n", hr); 611 612 IDirectInput8_Release(pDI); 613 } 614 615 static void test_GetDeviceStatus(void) 616 { 617 IDirectInput8A *pDI; 618 HRESULT hr; 619 620 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL); 621 if (FAILED(hr)) 622 { 623 win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr); 624 return; 625 } 626 627 hr = IDirectInput8_GetDeviceStatus(pDI, NULL); 628 ok(hr == E_POINTER, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr); 629 630 hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_Unknown); 631 todo_wine 632 ok(hr == DIERR_DEVICENOTREG, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr); 633 634 hr = IDirectInput8_GetDeviceStatus(pDI, &GUID_SysMouse); 635 ok(hr == DI_OK, "IDirectInput8_GetDeviceStatus returned 0x%08x\n", hr); 636 637 IDirectInput8_Release(pDI); 638 } 639 640 static void test_RunControlPanel(void) 641 { 642 IDirectInput8A *pDI; 643 HRESULT hr; 644 645 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL); 646 if (FAILED(hr)) 647 { 648 win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr); 649 return; 650 } 651 652 if (winetest_interactive) 653 { 654 hr = IDirectInput8_RunControlPanel(pDI, NULL, 0); 655 ok(hr == S_OK, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 656 657 hr = IDirectInput8_RunControlPanel(pDI, GetDesktopWindow(), 0); 658 ok(hr == S_OK, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 659 } 660 661 hr = IDirectInput8_RunControlPanel(pDI, NULL, ~0u); 662 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 663 664 hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, 0); 665 ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 666 667 hr = IDirectInput8_RunControlPanel(pDI, (HWND)0xdeadbeef, ~0u); 668 ok(hr == E_HANDLE, "IDirectInput8_RunControlPanel returned 0x%08x\n", hr); 669 670 IDirectInput8_Release(pDI); 671 } 672 673 static void test_Initialize(void) 674 { 675 IDirectInput8A *pDI; 676 HRESULT hr; 677 678 hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void **)&pDI, NULL); 679 if (FAILED(hr)) 680 { 681 win_skip("Failed to instantiate a IDirectInputA instance: 0x%08x\n", hr); 682 return; 683 } 684 685 hr = IDirectInput8_Initialize(pDI, NULL, 0); 686 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_Initialize returned 0x%08x\n", hr); 687 688 hr = IDirectInput8_Initialize(pDI, NULL, DIRECTINPUT_VERSION); 689 ok(hr == DIERR_INVALIDPARAM, "IDirectInput8_Initialize returned 0x%08x\n", hr); 690 691 hr = IDirectInput8_Initialize(pDI, hInstance, 0); 692 ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_Initialize returned 0x%08x\n", hr); 693 694 /* Invalid DirectInput versions less than DIRECTINPUT_VERSION yield DIERR_BETADIRECTINPUTVERSION. */ 695 hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION - 1); 696 ok(hr == DIERR_BETADIRECTINPUTVERSION, "IDirectInput8_Initialize returned 0x%08x\n", hr); 697 698 /* Invalid DirectInput versions greater than DIRECTINPUT_VERSION yield DIERR_BETADIRECTINPUTVERSION. */ 699 hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION + 1); 700 ok(hr == DIERR_OLDDIRECTINPUTVERSION, "IDirectInput8_Initialize returned 0x%08x\n", hr); 701 702 hr = IDirectInput8_Initialize(pDI, hInstance, DIRECTINPUT_VERSION); 703 ok(hr == DI_OK, "IDirectInput8_Initialize returned 0x%08x\n", hr); 704 705 /* Parameters are still validated after successful initialization. */ 706 hr = IDirectInput8_Initialize(pDI, hInstance, 0); 707 ok(hr == DIERR_NOTINITIALIZED, "IDirectInput8_Initialize returned 0x%08x\n", hr); 708 709 IDirectInput8_Release(pDI); 710 } 711 712 START_TEST(dinput) 713 { 714 hInstance = GetModuleHandleA(NULL); 715 716 CoInitialize(NULL); 717 test_preinitialization(); 718 test_DirectInput8Create(); 719 test_QueryInterface(); 720 test_CreateDevice(); 721 test_EnumDevices(); 722 test_EnumDevicesBySemantics(); 723 test_GetDeviceStatus(); 724 test_RunControlPanel(); 725 test_Initialize(); 726 CoUninitialize(); 727 } 728