1 /* 2 * Copyright (c) 2011 Lucas Fialho Zawacki 3 * Copyright (c) 2006 Vitaliy Margolen 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #define DIRECTINPUT_VERSION 0x0800 21 22 #define COBJMACROS 23 #include <windows.h> 24 25 #include "wine/test.h" 26 #include "windef.h" 27 #include "dinput.h" 28 29 struct enum_data { 30 IDirectInput8A *pDI; 31 DIACTIONFORMATA *lpdiaf; 32 IDirectInputDevice8A *keyboard; 33 IDirectInputDevice8A *mouse; 34 const char* username; 35 int ndevices; 36 }; 37 38 /* Dummy GUID */ 39 static const GUID ACTION_MAPPING_GUID = { 0x1, 0x2, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } }; 40 41 static const GUID NULL_GUID = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } }; 42 43 enum { 44 DITEST_AXIS, 45 DITEST_BUTTON, 46 DITEST_KEYBOARDSPACE, 47 DITEST_MOUSEBUTTON0, 48 DITEST_YAXIS 49 }; 50 51 static DIACTIONA actionMapping[]= 52 { 53 /* axis */ 54 { 0, 0x01008A01 /* DIAXIS_DRIVINGR_STEER */, 0, { "Steer.\0" } }, 55 /* button */ 56 { 1, 0x01000C01 /* DIBUTTON_DRIVINGR_SHIFTUP */, 0, { "Upshift.\0" } }, 57 /* keyboard key */ 58 { 2, DIKEYBOARD_SPACE, 0, { "Missile.\0" } }, 59 /* mouse button */ 60 { 3, DIMOUSE_BUTTON0, 0, { "Select\0" } }, 61 /* mouse axis */ 62 { 4, DIMOUSE_YAXIS, 0, { "Y Axis\0" } } 63 }; 64 /* By placing the memory pointed to by lptszActionName right before memory with PAGE_NOACCESS 65 * one can find out that the regular ansi string termination is not respected by EnumDevicesBySemantics. 66 * Adding a double termination, making it a valid wide string termination, made the test succeed. 67 * Therefore it looks like ansi version of EnumDevicesBySemantics forwards the string to 68 * the wide variant without conversation. */ 69 70 static void flush_events(void) 71 { 72 int diff = 200; 73 int min_timeout = 100; 74 DWORD time = GetTickCount() + diff; 75 76 while (diff > 0) 77 { 78 if (MsgWaitForMultipleObjects(0, NULL, FALSE, min_timeout, QS_ALLINPUT) == WAIT_TIMEOUT) 79 break; 80 diff = time - GetTickCount(); 81 min_timeout = 50; 82 } 83 } 84 85 static void test_device_input(IDirectInputDevice8A *lpdid, DWORD event_type, DWORD event, DWORD expected) 86 { 87 HRESULT hr; 88 DIDEVICEOBJECTDATA obj_data; 89 DWORD data_size = 1; 90 int i; 91 92 hr = IDirectInputDevice8_Acquire(lpdid); 93 ok (SUCCEEDED(hr), "Failed to acquire device hr=%08x\n", hr); 94 95 if (event_type == INPUT_KEYBOARD) 96 keybd_event( event, DIK_SPACE, 0, 0); 97 98 if (event_type == INPUT_MOUSE) 99 mouse_event( event, 0, 0, 0, 0); 100 101 flush_events(); 102 IDirectInputDevice8_Poll(lpdid); 103 hr = IDirectInputDevice8_GetDeviceData(lpdid, sizeof(obj_data), &obj_data, &data_size, 0); 104 105 if (data_size != 1) 106 { 107 win_skip("We're not able to inject input into Windows dinput8 with events\n"); 108 IDirectInputDevice_Unacquire(lpdid); 109 return; 110 } 111 112 ok (obj_data.uAppData == expected, "Retrieval of action failed uAppData=%lu expected=%d\n", obj_data.uAppData, expected); 113 114 /* Check for buffer overflow */ 115 for (i = 0; i < 17; i++) 116 if (event_type == INPUT_KEYBOARD) 117 { 118 keybd_event( VK_SPACE, DIK_SPACE, 0, 0); 119 keybd_event( VK_SPACE, DIK_SPACE, KEYEVENTF_KEYUP, 0); 120 } 121 else if (event_type == INPUT_MOUSE) 122 { 123 mouse_event(MOUSEEVENTF_LEFTDOWN, 1, 1, 0, 0); 124 mouse_event(MOUSEEVENTF_LEFTUP, 1, 1, 0, 0); 125 } 126 127 flush_events(); 128 IDirectInputDevice8_Poll(lpdid); 129 130 data_size = 1; 131 hr = IDirectInputDevice8_GetDeviceData(lpdid, sizeof(obj_data), &obj_data, &data_size, 0); 132 ok(hr == DI_BUFFEROVERFLOW, "GetDeviceData() failed: %08x\n", hr); 133 data_size = 1; 134 hr = IDirectInputDevice8_GetDeviceData(lpdid, sizeof(obj_data), &obj_data, &data_size, 0); 135 ok(hr == DI_OK && data_size == 1, "GetDeviceData() failed: %08x cnt:%d\n", hr, data_size); 136 137 IDirectInputDevice_Unacquire(lpdid); 138 } 139 140 static void test_build_action_map(IDirectInputDevice8A *lpdid, DIACTIONFORMATA *lpdiaf, 141 int action_index, DWORD expected_type, DWORD expected_inst) 142 { 143 HRESULT hr; 144 DIACTIONA *actions; 145 DWORD instance, type, how; 146 GUID assigned_to; 147 DIDEVICEINSTANCEA ddi; 148 149 ddi.dwSize = sizeof(ddi); 150 IDirectInputDevice_GetDeviceInfo(lpdid, &ddi); 151 152 hr = IDirectInputDevice8_BuildActionMap(lpdid, lpdiaf, NULL, DIDBAM_HWDEFAULTS); 153 ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr); 154 155 actions = lpdiaf->rgoAction; 156 instance = DIDFT_GETINSTANCE(actions[action_index].dwObjID); 157 type = DIDFT_GETTYPE(actions[action_index].dwObjID); 158 how = actions[action_index].dwHow; 159 assigned_to = actions[action_index].guidInstance; 160 161 ok (how == DIAH_USERCONFIG || how == DIAH_DEFAULT, "Action was not set dwHow=%08x\n", how); 162 ok (instance == expected_inst, "Action not mapped correctly instance=%08x expected=%08x\n", instance, expected_inst); 163 ok (type == expected_type, "Action type not mapped correctly type=%08x expected=%08x\n", type, expected_type); 164 ok (IsEqualGUID(&assigned_to, &ddi.guidInstance), "Action and device GUID do not match action=%d\n", action_index); 165 } 166 167 static BOOL CALLBACK enumeration_callback(const DIDEVICEINSTANCEA *lpddi, IDirectInputDevice8A *lpdid, 168 DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef) 169 { 170 HRESULT hr; 171 DIPROPDWORD dp; 172 DIPROPRANGE dpr; 173 DIPROPSTRING dps; 174 WCHAR usernameW[MAX_PATH]; 175 DWORD username_size = MAX_PATH; 176 struct enum_data *data = pvRef; 177 DWORD cnt; 178 DIDEVICEOBJECTDATA buffer[5]; 179 IDirectInputDevice8A *lpdid2; 180 181 if (!data) return DIENUM_CONTINUE; 182 183 data->ndevices++; 184 185 /* Convert username to WCHAR */ 186 if (data->username != NULL) 187 { 188 username_size = MultiByteToWideChar(CP_ACP, 0, data->username, -1, usernameW, 0); 189 MultiByteToWideChar(CP_ACP, 0, data->username, -1, usernameW, username_size); 190 } 191 else 192 GetUserNameW(usernameW, &username_size); 193 194 /* collect the mouse and keyboard */ 195 if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysKeyboard)) 196 { 197 IDirectInputDevice_AddRef(lpdid); 198 data->keyboard = lpdid; 199 200 ok (dwFlags & DIEDBS_MAPPEDPRI1, "Keyboard should be mapped as pri1 dwFlags=%08x\n", dwFlags); 201 } 202 203 if (IsEqualGUID(&lpddi->guidInstance, &GUID_SysMouse)) 204 { 205 IDirectInputDevice_AddRef(lpdid); 206 data->mouse = lpdid; 207 208 ok (dwFlags & DIEDBS_MAPPEDPRI1, "Mouse should be mapped as pri1 dwFlags=%08x\n", dwFlags); 209 } 210 211 /* Creating second device object to check if it has the same username */ 212 hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidInstance, &lpdid2, NULL); 213 ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr); 214 215 /* Building and setting an action map */ 216 /* It should not use any pre-stored mappings so we use DIDBAM_HWDEFAULTS */ 217 hr = IDirectInputDevice8_BuildActionMap(lpdid, data->lpdiaf, NULL, DIDBAM_HWDEFAULTS); 218 ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr); 219 220 /* Device has no data format and thus can't be acquired */ 221 hr = IDirectInputDevice8_Acquire(lpdid); 222 ok (hr == DIERR_INVALIDPARAM, "Device was acquired before SetActionMap hr=%08x\n", hr); 223 224 hr = IDirectInputDevice8_SetActionMap(lpdid, data->lpdiaf, data->username, 0); 225 ok (SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr); 226 227 /* Some joysticks may have no suitable actions and thus should not be tested */ 228 if (hr == DI_NOEFFECT) return DIENUM_CONTINUE; 229 230 /* Test username after SetActionMap */ 231 dps.diph.dwSize = sizeof(dps); 232 dps.diph.dwHeaderSize = sizeof(DIPROPHEADER); 233 dps.diph.dwObj = 0; 234 dps.diph.dwHow = DIPH_DEVICE; 235 dps.wsz[0] = '\0'; 236 237 hr = IDirectInputDevice_GetProperty(lpdid, DIPROP_USERNAME, &dps.diph); 238 ok (SUCCEEDED(hr), "GetProperty failed hr=%08x\n", hr); 239 ok (!lstrcmpW(usernameW, dps.wsz), "Username not set correctly expected=%s, got=%s\n", wine_dbgstr_w(usernameW), wine_dbgstr_w(dps.wsz)); 240 241 dps.wsz[0] = '\0'; 242 hr = IDirectInputDevice_GetProperty(lpdid2, DIPROP_USERNAME, &dps.diph); 243 ok (SUCCEEDED(hr), "GetProperty failed hr=%08x\n", hr); 244 ok (!lstrcmpW(usernameW, dps.wsz), "Username not set correctly expected=%s, got=%s\n", wine_dbgstr_w(usernameW), wine_dbgstr_w(dps.wsz)); 245 246 /* Test buffer size */ 247 memset(&dp, 0, sizeof(dp)); 248 dp.diph.dwSize = sizeof(dp); 249 dp.diph.dwHeaderSize = sizeof(DIPROPHEADER); 250 dp.diph.dwHow = DIPH_DEVICE; 251 252 hr = IDirectInputDevice_GetProperty(lpdid, DIPROP_BUFFERSIZE, &dp.diph); 253 ok (SUCCEEDED(hr), "GetProperty failed hr=%08x\n", hr); 254 ok (dp.dwData == data->lpdiaf->dwBufferSize, "SetActionMap must set the buffer, buffersize=%d\n", dp.dwData); 255 256 cnt = 1; 257 hr = IDirectInputDevice_GetDeviceData(lpdid, sizeof(buffer[0]), buffer, &cnt, 0); 258 ok(hr == DIERR_NOTACQUIRED, "GetDeviceData() failed hr=%08x\n", hr); 259 260 /* Test axis range */ 261 memset(&dpr, 0, sizeof(dpr)); 262 dpr.diph.dwSize = sizeof(dpr); 263 dpr.diph.dwHeaderSize = sizeof(DIPROPHEADER); 264 dpr.diph.dwHow = DIPH_DEVICE; 265 266 hr = IDirectInputDevice_GetProperty(lpdid, DIPROP_RANGE, &dpr.diph); 267 /* Only test if device supports the range property */ 268 if (SUCCEEDED(hr)) 269 { 270 ok (dpr.lMin == data->lpdiaf->lAxisMin, "SetActionMap must set the min axis range expected=%d got=%d\n", data->lpdiaf->lAxisMin, dpr.lMin); 271 ok (dpr.lMax == data->lpdiaf->lAxisMax, "SetActionMap must set the max axis range expected=%d got=%d\n", data->lpdiaf->lAxisMax, dpr.lMax); 272 } 273 274 /* SetActionMap has set the data format so now it should work */ 275 hr = IDirectInputDevice8_Acquire(lpdid); 276 ok (SUCCEEDED(hr), "Acquire failed hr=%08x\n", hr); 277 278 cnt = 1; 279 hr = IDirectInputDevice_GetDeviceData(lpdid, sizeof(buffer[0]), buffer, &cnt, 0); 280 ok(hr == DI_OK, "GetDeviceData() failed hr=%08x\n", hr); 281 282 /* SetActionMap should not work on an acquired device */ 283 hr = IDirectInputDevice8_SetActionMap(lpdid, data->lpdiaf, NULL, 0); 284 ok (hr == DIERR_ACQUIRED, "SetActionMap succeeded with an acquired device hr=%08x\n", hr); 285 286 IDirectInputDevice_Release(lpdid2); 287 288 return DIENUM_CONTINUE; 289 } 290 291 static void test_action_mapping(void) 292 { 293 HRESULT hr; 294 HINSTANCE hinst = GetModuleHandleA(NULL); 295 IDirectInput8A *pDI = NULL; 296 DIACTIONFORMATA af; 297 DIPROPSTRING dps; 298 struct enum_data data = {pDI, &af, NULL, NULL, NULL, 0}; 299 HWND hwnd; 300 301 hr = CoCreateInstance(&CLSID_DirectInput8, 0, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (LPVOID*)&pDI); 302 if (hr == DIERR_OLDDIRECTINPUTVERSION || 303 hr == DIERR_BETADIRECTINPUTVERSION || 304 hr == REGDB_E_CLASSNOTREG) 305 { 306 win_skip("ActionMapping requires dinput8\n"); 307 return; 308 } 309 ok(SUCCEEDED(hr), "DirectInput8 Create failed: hr=%08x\n", hr); 310 if (FAILED(hr)) return; 311 312 hr = IDirectInput8_Initialize(pDI,hinst, DIRECTINPUT_VERSION); 313 if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_BETADIRECTINPUTVERSION) 314 { 315 win_skip("ActionMapping requires dinput8\n"); 316 return; 317 } 318 ok(SUCCEEDED(hr), "DirectInput8 Initialize failed: hr=%08x\n", hr); 319 if (FAILED(hr)) return; 320 321 memset (&af, 0, sizeof(af)); 322 af.dwSize = sizeof(af); 323 af.dwActionSize = sizeof(DIACTIONA); 324 af.dwDataSize = 4 * ARRAY_SIZE(actionMapping); 325 af.dwNumActions = ARRAY_SIZE(actionMapping); 326 af.rgoAction = actionMapping; 327 af.guidActionMap = ACTION_MAPPING_GUID; 328 af.dwGenre = 0x01000000; /* DIVIRTUAL_DRIVING_RACE */ 329 af.dwBufferSize = 32; 330 331 /* This enumeration builds and sets the action map for all devices */ 332 data.pDI = pDI; 333 hr = IDirectInput8_EnumDevicesBySemantics(pDI, 0, &af, enumeration_callback, &data, DIEDBSFL_ATTACHEDONLY); 334 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr); 335 336 if (data.keyboard) 337 IDirectInputDevice_Release(data.keyboard); 338 339 if (data.mouse) 340 IDirectInputDevice_Release(data.mouse); 341 342 /* Repeat tests with a non NULL user */ 343 data.username = "Ninja Brian"; 344 hr = IDirectInput8_EnumDevicesBySemantics(pDI, NULL, &af, enumeration_callback, &data, DIEDBSFL_ATTACHEDONLY); 345 ok (SUCCEEDED(hr), "EnumDevicesBySemantics failed: hr=%08x\n", hr); 346 347 hwnd = CreateWindowExA(WS_EX_TOPMOST, "static", "dinput", 348 WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); 349 ok(hwnd != NULL, "failed to create window\n"); 350 SetCursorPos(50, 50); 351 352 if (data.keyboard != NULL) 353 { 354 /* Test keyboard BuildActionMap */ 355 test_build_action_map(data.keyboard, data.lpdiaf, DITEST_KEYBOARDSPACE, DIDFT_PSHBUTTON, DIK_SPACE); 356 /* Test keyboard input */ 357 test_device_input(data.keyboard, INPUT_KEYBOARD, VK_SPACE, 2); 358 359 /* Test BuildActionMap with no suitable actions for a device */ 360 IDirectInputDevice_Unacquire(data.keyboard); 361 af.dwDataSize = 4 * DITEST_KEYBOARDSPACE; 362 af.dwNumActions = DITEST_KEYBOARDSPACE; 363 364 hr = IDirectInputDevice8_BuildActionMap(data.keyboard, data.lpdiaf, NULL, DIDBAM_HWDEFAULTS); 365 ok (hr == DI_NOEFFECT, "BuildActionMap should have no effect with no actions hr=%08x\n", hr); 366 367 hr = IDirectInputDevice8_SetActionMap(data.keyboard, data.lpdiaf, NULL, 0); 368 ok (hr == DI_NOEFFECT, "SetActionMap should have no effect with no actions to map hr=%08x\n", hr); 369 370 /* Test that after changing actionformat SetActionMap has effect and that second 371 * SetActionMap call with same empty actionformat has no effect */ 372 af.dwDataSize = 4 * 1; 373 af.dwNumActions = 1; 374 375 hr = IDirectInputDevice8_SetActionMap(data.keyboard, data.lpdiaf, NULL, 0); 376 ok (hr != DI_NOEFFECT, "SetActionMap should have effect as actionformat has changed hr=%08x\n", hr); 377 378 hr = IDirectInputDevice8_SetActionMap(data.keyboard, data.lpdiaf, NULL, 0); 379 ok (hr == DI_NOEFFECT, "SetActionMap should have no effect with no actions to map hr=%08x\n", hr); 380 381 af.dwDataSize = 4 * ARRAY_SIZE(actionMapping); 382 af.dwNumActions = ARRAY_SIZE(actionMapping); 383 384 /* test DIDSAM_NOUSER */ 385 dps.diph.dwSize = sizeof(dps); 386 dps.diph.dwHeaderSize = sizeof(DIPROPHEADER); 387 dps.diph.dwObj = 0; 388 dps.diph.dwHow = DIPH_DEVICE; 389 dps.wsz[0] = '\0'; 390 391 hr = IDirectInputDevice_GetProperty(data.keyboard, DIPROP_USERNAME, &dps.diph); 392 ok (SUCCEEDED(hr), "GetProperty failed hr=%08x\n", hr); 393 ok (dps.wsz[0] != 0, "Expected any username, got=%s\n", wine_dbgstr_w(dps.wsz)); 394 395 hr = IDirectInputDevice8_SetActionMap(data.keyboard, data.lpdiaf, NULL, DIDSAM_NOUSER); 396 ok (SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr); 397 398 dps.diph.dwSize = sizeof(dps); 399 dps.diph.dwHeaderSize = sizeof(DIPROPHEADER); 400 dps.diph.dwObj = 0; 401 dps.diph.dwHow = DIPH_DEVICE; 402 dps.wsz[0] = '\0'; 403 404 hr = IDirectInputDevice_GetProperty(data.keyboard, DIPROP_USERNAME, &dps.diph); 405 ok (SUCCEEDED(hr), "GetProperty failed hr=%08x\n", hr); 406 ok (dps.wsz[0] == 0, "Expected empty username, got=%s\n", wine_dbgstr_w(dps.wsz)); 407 408 IDirectInputDevice_Release(data.keyboard); 409 } 410 411 if (data.mouse != NULL) 412 { 413 /* Test mouse BuildActionMap */ 414 test_build_action_map(data.mouse, data.lpdiaf, DITEST_MOUSEBUTTON0, DIDFT_PSHBUTTON, 0x03); 415 test_build_action_map(data.mouse, data.lpdiaf, DITEST_YAXIS, DIDFT_RELAXIS, 0x01); 416 417 test_device_input(data.mouse, INPUT_MOUSE, MOUSEEVENTF_LEFTDOWN, 3); 418 419 IDirectInputDevice_Release(data.mouse); 420 } 421 422 DestroyWindow(hwnd); 423 IDirectInput_Release(pDI); 424 } 425 426 static void test_save_settings(void) 427 { 428 HRESULT hr; 429 HINSTANCE hinst = GetModuleHandleA(NULL); 430 IDirectInput8A *pDI = NULL; 431 DIACTIONFORMATA af; 432 IDirectInputDevice8A *pKey; 433 434 static const GUID mapping_guid = { 0xcafecafe, 0x2, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } }; 435 static const GUID other_guid = { 0xcafe, 0xcafe, 0x3, { 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb } }; 436 437 static DIACTIONA actions[] = { 438 { 0, DIKEYBOARD_A , 0, { "Blam" } }, 439 { 1, DIKEYBOARD_B , 0, { "Kapow"} } 440 }; 441 static const DWORD results[] = { 442 DIDFT_MAKEINSTANCE(DIK_A) | DIDFT_PSHBUTTON, 443 DIDFT_MAKEINSTANCE(DIK_B) | DIDFT_PSHBUTTON 444 }; 445 static const DWORD other_results[] = { 446 DIDFT_MAKEINSTANCE(DIK_C) | DIDFT_PSHBUTTON, 447 DIDFT_MAKEINSTANCE(DIK_D) | DIDFT_PSHBUTTON 448 }; 449 450 hr = CoCreateInstance(&CLSID_DirectInput8, 0, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (LPVOID*)&pDI); 451 if (hr == DIERR_OLDDIRECTINPUTVERSION || 452 hr == DIERR_BETADIRECTINPUTVERSION || 453 hr == REGDB_E_CLASSNOTREG) 454 { 455 win_skip("ActionMapping requires dinput8\n"); 456 return; 457 } 458 ok (SUCCEEDED(hr), "DirectInput8 Create failed: hr=%08x\n", hr); 459 if (FAILED(hr)) return; 460 461 hr = IDirectInput8_Initialize(pDI,hinst, DIRECTINPUT_VERSION); 462 if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_BETADIRECTINPUTVERSION) 463 { 464 win_skip("ActionMapping requires dinput8\n"); 465 return; 466 } 467 ok (SUCCEEDED(hr), "DirectInput8 Initialize failed: hr=%08x\n", hr); 468 if (FAILED(hr)) return; 469 470 hr = IDirectInput_CreateDevice(pDI, &GUID_SysKeyboard, &pKey, NULL); 471 ok (SUCCEEDED(hr), "IDirectInput_Create device failed hr: 0x%08x\n", hr); 472 if (FAILED(hr)) return; 473 474 memset (&af, 0, sizeof(af)); 475 af.dwSize = sizeof(af); 476 af.dwActionSize = sizeof(DIACTIONA); 477 af.dwDataSize = 4 * ARRAY_SIZE(actions); 478 af.dwNumActions = ARRAY_SIZE(actions); 479 af.rgoAction = actions; 480 af.guidActionMap = mapping_guid; 481 af.dwGenre = 0x01000000; /* DIVIRTUAL_DRIVING_RACE */ 482 af.dwBufferSize = 32; 483 484 /* Easy case. Ask for default mapping, save, ask for previous map and read it back */ 485 hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, DIDBAM_HWDEFAULTS); 486 ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr); 487 ok (results[0] == af.rgoAction[0].dwObjID, 488 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", results[0], af.rgoAction[0].dwObjID); 489 490 ok (results[1] == af.rgoAction[1].dwObjID, 491 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", results[1], af.rgoAction[1].dwObjID); 492 493 hr = IDirectInputDevice8_SetActionMap(pKey, &af, NULL, DIDSAM_FORCESAVE); 494 ok (SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr); 495 496 if (hr == DI_SETTINGSNOTSAVED) 497 { 498 skip ("Can't test saving settings if SetActionMap returns DI_SETTINGSNOTSAVED\n"); 499 return; 500 } 501 502 af.rgoAction[0].dwObjID = 0; 503 af.rgoAction[1].dwObjID = 0; 504 memset(&af.rgoAction[0].guidInstance, 0, sizeof(GUID)); 505 memset(&af.rgoAction[1].guidInstance, 0, sizeof(GUID)); 506 507 hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, 0); 508 ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr); 509 510 ok (results[0] == af.rgoAction[0].dwObjID, 511 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", results[0], af.rgoAction[0].dwObjID); 512 ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[0].guidInstance), "Action should be mapped to keyboard\n"); 513 514 ok (results[1] == af.rgoAction[1].dwObjID, 515 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", results[1], af.rgoAction[1].dwObjID); 516 ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[1].guidInstance), "Action should be mapped to keyboard\n"); 517 518 /* Test that a different action map with no pre-stored settings, in spite of the flags, 519 does not try to load mappings and instead applies the default mapping */ 520 af.guidActionMap = other_guid; 521 522 af.rgoAction[0].dwObjID = 0; 523 af.rgoAction[1].dwObjID = 0; 524 memset(&af.rgoAction[0].guidInstance, 0, sizeof(GUID)); 525 memset(&af.rgoAction[1].guidInstance, 0, sizeof(GUID)); 526 527 hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, 0); 528 ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr); 529 530 ok (results[0] == af.rgoAction[0].dwObjID, 531 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", results[0], af.rgoAction[0].dwObjID); 532 ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[0].guidInstance), "Action should be mapped to keyboard\n"); 533 534 ok (results[1] == af.rgoAction[1].dwObjID, 535 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", results[1], af.rgoAction[1].dwObjID); 536 ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[1].guidInstance), "Action should be mapped to keyboard\n"); 537 538 af.guidActionMap = mapping_guid; 539 /* Hard case. Customized mapping, save, ask for previous map and read it back */ 540 af.rgoAction[0].dwObjID = other_results[0]; 541 af.rgoAction[0].dwHow = DIAH_USERCONFIG; 542 af.rgoAction[0].guidInstance = GUID_SysKeyboard; 543 af.rgoAction[1].dwObjID = other_results[1]; 544 af.rgoAction[1].dwHow = DIAH_USERCONFIG; 545 af.rgoAction[1].guidInstance = GUID_SysKeyboard; 546 547 hr = IDirectInputDevice8_SetActionMap(pKey, &af, NULL, DIDSAM_FORCESAVE); 548 ok (SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr); 549 550 if (hr == DI_SETTINGSNOTSAVED) 551 { 552 skip ("Can't test saving settings if SetActionMap returns DI_SETTINGSNOTSAVED\n"); 553 return; 554 } 555 556 af.rgoAction[0].dwObjID = 0; 557 af.rgoAction[1].dwObjID = 0; 558 memset(&af.rgoAction[0].guidInstance, 0, sizeof(GUID)); 559 memset(&af.rgoAction[1].guidInstance, 0, sizeof(GUID)); 560 561 hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, 0); 562 ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr); 563 564 ok (other_results[0] == af.rgoAction[0].dwObjID, 565 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", other_results[0], af.rgoAction[0].dwObjID); 566 ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[0].guidInstance), "Action should be mapped to keyboard\n"); 567 568 ok (other_results[1] == af.rgoAction[1].dwObjID, 569 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", other_results[1], af.rgoAction[1].dwObjID); 570 ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[1].guidInstance), "Action should be mapped to keyboard\n"); 571 572 /* Save and load empty mapping */ 573 af.rgoAction[0].dwObjID = 0; 574 af.rgoAction[0].dwHow = 0; 575 memset(&af.rgoAction[0].guidInstance, 0, sizeof(GUID)); 576 af.rgoAction[1].dwObjID = 0; 577 af.rgoAction[1].dwHow = 0; 578 memset(&af.rgoAction[1].guidInstance, 0, sizeof(GUID)); 579 580 hr = IDirectInputDevice8_SetActionMap(pKey, &af, NULL, DIDSAM_FORCESAVE); 581 ok (SUCCEEDED(hr), "SetActionMap failed hr=%08x\n", hr); 582 583 if (hr == DI_SETTINGSNOTSAVED) 584 { 585 skip ("Can't test saving settings if SetActionMap returns DI_SETTINGSNOTSAVED\n"); 586 return; 587 } 588 589 af.rgoAction[0].dwObjID = other_results[0]; 590 af.rgoAction[0].dwHow = DIAH_USERCONFIG; 591 af.rgoAction[0].guidInstance = GUID_SysKeyboard; 592 af.rgoAction[1].dwObjID = other_results[1]; 593 af.rgoAction[1].dwHow = DIAH_USERCONFIG; 594 af.rgoAction[1].guidInstance = GUID_SysKeyboard; 595 596 hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, 0); 597 ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr); 598 599 ok (other_results[0] == af.rgoAction[0].dwObjID, 600 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", other_results[0], af.rgoAction[0].dwObjID); 601 ok (af.rgoAction[0].dwHow == DIAH_UNMAPPED, "dwHow should have been DIAH_UNMAPPED\n"); 602 ok (IsEqualGUID(&NULL_GUID, &af.rgoAction[0].guidInstance), "Action should not be mapped\n"); 603 604 ok (other_results[1] == af.rgoAction[1].dwObjID, 605 "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", other_results[1], af.rgoAction[1].dwObjID); 606 ok (af.rgoAction[1].dwHow == DIAH_UNMAPPED, "dwHow should have been DIAH_UNMAPPED\n"); 607 ok (IsEqualGUID(&NULL_GUID, &af.rgoAction[1].guidInstance), "Action should not be mapped\n"); 608 609 IDirectInputDevice_Release(pKey); 610 IDirectInput_Release(pDI); 611 } 612 613 static void test_mouse_keyboard(void) 614 { 615 HRESULT hr; 616 HWND hwnd, di_hwnd = INVALID_HANDLE_VALUE; 617 IDirectInput8A *di = NULL; 618 IDirectInputDevice8A *di_mouse, *di_keyboard; 619 UINT raw_devices_count; 620 RAWINPUTDEVICE raw_devices[3]; 621 622 hwnd = CreateWindowExA(WS_EX_TOPMOST, "static", "dinput", WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL); 623 ok(hwnd != NULL, "CreateWindowExA failed\n"); 624 625 hr = CoCreateInstance(&CLSID_DirectInput8, 0, CLSCTX_INPROC_SERVER, &IID_IDirectInput8A, (LPVOID*)&di); 626 if (hr == DIERR_OLDDIRECTINPUTVERSION || 627 hr == DIERR_BETADIRECTINPUTVERSION || 628 hr == REGDB_E_CLASSNOTREG) 629 { 630 win_skip("test_mouse_keyboard requires dinput8\n"); 631 return; 632 } 633 ok(SUCCEEDED(hr), "DirectInput8Create failed: %08x\n", hr); 634 635 hr = IDirectInput8_Initialize(di, GetModuleHandleA(NULL), DIRECTINPUT_VERSION); 636 if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_BETADIRECTINPUTVERSION) 637 { 638 win_skip("test_mouse_keyboard requires dinput8\n"); 639 return; 640 } 641 ok(SUCCEEDED(hr), "IDirectInput8_Initialize failed: %08x\n", hr); 642 643 hr = IDirectInput8_CreateDevice(di, &GUID_SysMouse, &di_mouse, NULL); 644 ok(SUCCEEDED(hr), "IDirectInput8_CreateDevice failed: %08x\n", hr); 645 hr = IDirectInputDevice8_SetDataFormat(di_mouse, &c_dfDIMouse); 646 ok(SUCCEEDED(hr), "IDirectInputDevice8_SetDataFormat failed: %08x\n", hr); 647 648 hr = IDirectInput8_CreateDevice(di, &GUID_SysKeyboard, &di_keyboard, NULL); 649 ok(SUCCEEDED(hr), "IDirectInput8_CreateDevice failed: %08x\n", hr); 650 hr = IDirectInputDevice8_SetDataFormat(di_keyboard, &c_dfDIKeyboard); 651 ok(SUCCEEDED(hr), "IDirectInputDevice8_SetDataFormat failed: %08x\n", hr); 652 653 raw_devices_count = ARRAY_SIZE(raw_devices); 654 GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); 655 todo_wine 656 ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count); 657 658 hr = IDirectInputDevice8_Acquire(di_keyboard); 659 ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); 660 raw_devices_count = ARRAY_SIZE(raw_devices); 661 memset(raw_devices, 0, sizeof(raw_devices)); 662 hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); 663 todo_wine 664 ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); 665 todo_wine 666 ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); 667 todo_wine 668 ok(raw_devices[0].usUsage == 6, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); 669 todo_wine 670 ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); 671 todo_wine 672 ok(raw_devices[0].hwndTarget != NULL, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); 673 hr = IDirectInputDevice8_Unacquire(di_keyboard); 674 ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); 675 raw_devices_count = ARRAY_SIZE(raw_devices); 676 GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); 677 todo_wine 678 ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count); 679 680 if (raw_devices[0].hwndTarget != NULL) 681 { 682 WCHAR di_hwnd_class[] = {'D','I','E','m','W','i','n',0}; 683 WCHAR str[16]; 684 int i; 685 686 di_hwnd = raw_devices[0].hwndTarget; 687 i = GetClassNameW(di_hwnd, str, ARRAY_SIZE(str)); 688 ok(i == lstrlenW(di_hwnd_class), "GetClassName returned incorrect length\n"); 689 ok(!lstrcmpW(di_hwnd_class, str), "GetClassName returned incorrect name for this window's class\n"); 690 691 i = GetWindowTextW(di_hwnd, str, ARRAY_SIZE(str)); 692 ok(i == lstrlenW(di_hwnd_class), "GetClassName returned incorrect length\n"); 693 ok(!lstrcmpW(di_hwnd_class, str), "GetClassName returned incorrect name for this window's class\n"); 694 } 695 696 hr = IDirectInputDevice8_Acquire(di_mouse); 697 ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); 698 raw_devices_count = ARRAY_SIZE(raw_devices); 699 memset(raw_devices, 0, sizeof(raw_devices)); 700 hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); 701 todo_wine 702 ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); 703 todo_wine 704 ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); 705 todo_wine 706 ok(raw_devices[0].usUsage == 2, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); 707 todo_wine 708 ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); 709 todo_wine 710 ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); 711 hr = IDirectInputDevice8_Unacquire(di_mouse); 712 ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); 713 raw_devices_count = ARRAY_SIZE(raw_devices); 714 GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); 715 todo_wine 716 ok(raw_devices_count == 0, "Unexpected raw devices registered: %d\n", raw_devices_count); 717 718 /* expect dinput8 to take over any activated raw input devices */ 719 raw_devices[0].usUsagePage = 0x01; 720 raw_devices[0].usUsage = 0x05; 721 raw_devices[0].dwFlags = 0; 722 raw_devices[0].hwndTarget = hwnd; 723 raw_devices[1].usUsagePage = 0x01; 724 raw_devices[1].usUsage = 0x06; 725 raw_devices[1].dwFlags = 0; 726 raw_devices[1].hwndTarget = hwnd; 727 raw_devices[2].usUsagePage = 0x01; 728 raw_devices[2].usUsage = 0x02; 729 raw_devices[2].dwFlags = 0; 730 raw_devices[2].hwndTarget = hwnd; 731 raw_devices_count = ARRAY_SIZE(raw_devices); 732 hr = RegisterRawInputDevices(raw_devices, raw_devices_count, sizeof(RAWINPUTDEVICE)); 733 ok(hr == TRUE, "RegisterRawInputDevices failed\n"); 734 735 hr = IDirectInputDevice8_Acquire(di_keyboard); 736 ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); 737 hr = IDirectInputDevice8_Acquire(di_mouse); 738 ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); 739 raw_devices_count = ARRAY_SIZE(raw_devices); 740 memset(raw_devices, 0, sizeof(raw_devices)); 741 hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); 742 todo_wine 743 ok(hr == 3, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); 744 todo_wine 745 ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); 746 todo_wine 747 ok(raw_devices[0].usUsage == 2, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); 748 todo_wine 749 ok(raw_devices[0].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); 750 todo_wine 751 ok(raw_devices[0].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); 752 todo_wine 753 ok(raw_devices[1].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); 754 todo_wine 755 ok(raw_devices[1].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); 756 ok(raw_devices[1].dwFlags == 0, "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); 757 todo_wine 758 ok(raw_devices[1].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[1].hwndTarget); 759 todo_wine 760 ok(raw_devices[2].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[1].usUsagePage); 761 todo_wine 762 ok(raw_devices[2].usUsage == 6, "Unexpected raw device usage: %x\n", raw_devices[1].usUsage); 763 todo_wine 764 ok(raw_devices[2].dwFlags == RIDEV_INPUTSINK, "Unexpected raw device flags: %x\n", raw_devices[1].dwFlags); 765 todo_wine 766 ok(raw_devices[2].hwndTarget == di_hwnd, "Unexpected raw device target: %p\n", raw_devices[1].hwndTarget); 767 hr = IDirectInputDevice8_Unacquire(di_keyboard); 768 ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); 769 hr = IDirectInputDevice8_Unacquire(di_mouse); 770 ok(SUCCEEDED(hr), "IDirectInputDevice8_Acquire failed: %08x\n", hr); 771 raw_devices_count = ARRAY_SIZE(raw_devices); 772 GetRegisteredRawInputDevices(NULL, &raw_devices_count, sizeof(RAWINPUTDEVICE)); 773 todo_wine 774 ok(raw_devices_count == 1, "Unexpected raw devices registered: %d\n", raw_devices_count); 775 776 raw_devices_count = ARRAY_SIZE(raw_devices); 777 hr = GetRegisteredRawInputDevices(raw_devices, &raw_devices_count, sizeof(RAWINPUTDEVICE)); 778 todo_wine 779 ok(hr == 1, "GetRegisteredRawInputDevices returned %d, raw_devices_count: %d\n", hr, raw_devices_count); 780 todo_wine 781 ok(raw_devices[0].usUsagePage == 1, "Unexpected raw device usage page: %x\n", raw_devices[0].usUsagePage); 782 todo_wine 783 ok(raw_devices[0].usUsage == 5, "Unexpected raw device usage: %x\n", raw_devices[0].usUsage); 784 ok(raw_devices[0].dwFlags == 0, "Unexpected raw device flags: %x\n", raw_devices[0].dwFlags); 785 todo_wine 786 ok(raw_devices[0].hwndTarget == hwnd, "Unexpected raw device target: %p\n", raw_devices[0].hwndTarget); 787 788 IDirectInputDevice8_Release(di_mouse); 789 IDirectInputDevice8_Release(di_keyboard); 790 IDirectInput8_Release(di); 791 792 DestroyWindow(hwnd); 793 } 794 795 START_TEST(device) 796 { 797 CoInitialize(NULL); 798 799 test_action_mapping(); 800 test_save_settings(); 801 test_mouse_keyboard(); 802 803 CoUninitialize(); 804 } 805