1 /* 2 * Copyright (c) 2006 Vitaliy Margolen 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 0x0700 20 21 #define COBJMACROS 22 #include <windows.h> 23 24 #include "wine/test.h" 25 #include "windef.h" 26 #include "dinput.h" 27 28 static const DIOBJECTDATAFORMAT obj_data_format[] = { 29 { &GUID_YAxis, 16, DIDFT_OPTIONAL|DIDFT_AXIS |DIDFT_MAKEINSTANCE(1), 0}, 30 { &GUID_Button,15, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(3), 0}, 31 { &GUID_Key, 0, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(16),0}, 32 { &GUID_Key, 1, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(17),0}, 33 { &GUID_Key, 2, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(18),0}, 34 { &GUID_Key, 3, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(19),0}, 35 { &GUID_Key, 4, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(20),0}, 36 { &GUID_Key, 5, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(21),0}, 37 { &GUID_Key, 6, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(22),0}, 38 { &GUID_Key, 7, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(23),0}, 39 { &GUID_Key, 8, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(24),0}, 40 { &GUID_Key, 9, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(25),0}, 41 { &GUID_Key, 10, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(26),0}, 42 { &GUID_Key, 11, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(27),0}, 43 { &GUID_Key, 12, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(28),0}, 44 { NULL, 13, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(5),0}, 45 46 { &GUID_Button,14, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(32),0} 47 }; 48 49 static const DIDATAFORMAT data_format = { 50 sizeof(DIDATAFORMAT), 51 sizeof(DIOBJECTDATAFORMAT), 52 DIDF_ABSAXIS, 53 32, 54 ARRAY_SIZE(obj_data_format), 55 (LPDIOBJECTDATAFORMAT)obj_data_format 56 }; 57 58 static BOOL CALLBACK enum_callback(const DIDEVICEOBJECTINSTANCEA *oi, void *info) 59 { 60 if (winetest_debug > 1) 61 trace(" Type:%4x Ofs:%3d Flags:%08x Name:%s\n", 62 oi->dwType, oi->dwOfs, oi->dwFlags, oi->tszName); 63 (*(int*)info)++; 64 return DIENUM_CONTINUE; 65 } 66 67 static BOOL CALLBACK enum_type_callback(const DIDEVICEOBJECTINSTANCEA *oi, void *info) 68 { 69 DWORD expected = *(DWORD*)info; 70 ok (expected & DIDFT_GETTYPE(oi->dwType), "EnumObjects() enumerated wrong type for obj %s, expected: %08x got: %08x\n", oi->tszName, expected, oi->dwType); 71 return DIENUM_CONTINUE; 72 } 73 74 static void test_object_info(IDirectInputDeviceA *device, HWND hwnd) 75 { 76 HRESULT hr; 77 DIPROPDWORD dp; 78 DIDEVICEOBJECTINSTANCEA obj_info; 79 DWORD obj_types[] = {DIDFT_BUTTON, DIDFT_AXIS, DIDFT_POV}; 80 int type_index; 81 int cnt1 = 0; 82 DWORD cnt = 0; 83 DIDEVICEOBJECTDATA buffer[5]; 84 85 hr = IDirectInputDevice_EnumObjects(device, enum_callback, &cnt, DIDFT_ALL); 86 ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr); 87 88 hr = IDirectInputDevice_SetDataFormat(device, &data_format); 89 ok(SUCCEEDED(hr), "SetDataFormat() failed: %08x\n", hr); 90 91 hr = IDirectInputDevice_EnumObjects(device, enum_callback, &cnt1, DIDFT_ALL); 92 ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr); 93 if (0) /* fails for joystick only */ 94 ok(cnt == cnt1, "Enum count changed from %d to %d\n", cnt, cnt1); 95 96 /* Testing EnumObjects with different types of device objects */ 97 for (type_index=0; type_index < ARRAY_SIZE(obj_types); type_index++) 98 { 99 hr = IDirectInputDevice_EnumObjects(device, enum_type_callback, &obj_types[type_index], obj_types[type_index]); 100 ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr); 101 } 102 103 /* Test buffered mode */ 104 memset(&dp, 0, sizeof(dp)); 105 dp.diph.dwSize = sizeof(DIPROPDWORD); 106 dp.diph.dwHeaderSize = sizeof(DIPROPHEADER); 107 dp.diph.dwHow = DIPH_DEVICE; 108 dp.diph.dwObj = 0; 109 dp.dwData = 0; 110 111 hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph); 112 ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr); 113 cnt = 5; 114 hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0); 115 ok(hr == DI_OK && cnt == 5, "GetDeviceData() failed: %08x cnt: %d\n", hr, cnt); 116 hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0); 117 ok(hr == DIERR_NOTBUFFERED, "GetDeviceData() should have failed: %08x\n", hr); 118 IDirectInputDevice_Acquire(device); 119 hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0); 120 ok(hr == DIERR_NOTBUFFERED, "GetDeviceData() should have failed: %08x\n", hr); 121 IDirectInputDevice_Unacquire(device); 122 123 dp.dwData = 20; 124 hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph); 125 ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr); 126 cnt = 5; 127 hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0); 128 ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr); 129 hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0); 130 ok(hr == DIERR_NOTACQUIRED, "GetDeviceData() should have failed: %08x\n", hr); 131 hr = IDirectInputDevice_Acquire(device); 132 ok(hr == DI_OK, "Acquire() failed: %08x\n", hr); 133 cnt = 1; 134 hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0); 135 ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr); 136 hr = IDirectInputDevice_Unacquire(device); 137 ok(hr == DI_OK, "Unacquire() failed: %08x\n", hr); 138 cnt = 1; 139 hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0); 140 ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr); 141 142 /* No need to test devices without axis */ 143 obj_info.dwSize = sizeof(obj_info); 144 hr = IDirectInputDevice_GetObjectInfo(device, &obj_info, 16, DIPH_BYOFFSET); 145 if (SUCCEEDED(hr)) 146 { 147 /* No device supports per axis relative/absolute mode */ 148 dp.diph.dwHow = DIPH_BYOFFSET; 149 dp.diph.dwObj = 16; 150 dp.dwData = DIPROPAXISMODE_ABS; 151 hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph); 152 ok(hr == DIERR_UNSUPPORTED, "SetProperty() returned: %08x\n", hr); 153 dp.diph.dwHow = DIPH_DEVICE; 154 hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph); 155 ok(hr == DIERR_INVALIDPARAM, "SetProperty() returned: %08x\n", hr); 156 dp.diph.dwObj = 0; 157 hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph); 158 ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr); 159 160 /* Cannot change mode while acquired */ 161 hr = IDirectInputDevice_Acquire(device); 162 ok(hr == DI_OK, "Acquire() failed: %08x\n", hr); 163 164 hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph); 165 ok(hr == DIERR_ACQUIRED, "SetProperty() returned: %08x\n", hr); 166 hr = IDirectInputDevice_Unacquire(device); 167 ok(hr == DI_OK, "Unacquire() failed: %08x\n", hr); 168 } 169 } 170 171 struct enum_data 172 { 173 IDirectInputA *pDI; 174 HWND hwnd; 175 }; 176 177 static BOOL CALLBACK enum_devices(const DIDEVICEINSTANCEA *lpddi, void *pvRef) 178 { 179 struct enum_data *data = pvRef; 180 IDirectInputDeviceA *device, *obj = NULL; 181 HRESULT hr; 182 183 hr = IDirectInput_GetDeviceStatus(data->pDI, &lpddi->guidInstance); 184 ok(hr == DI_OK, "IDirectInput_GetDeviceStatus() failed: %08x\n", hr); 185 186 if (hr == DI_OK) 187 { 188 hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidInstance, &device, NULL); 189 ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr); 190 trace("Testing device %p \"%s\"\n", device, lpddi->tszInstanceName); 191 192 hr = IUnknown_QueryInterface(device, &IID_IDirectInputDevice2A, (LPVOID*)&obj); 193 ok(SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice7A) failed: %08x\n", hr); 194 test_object_info(obj, data->hwnd); 195 if (obj) IUnknown_Release(obj); 196 obj = NULL; 197 198 hr = IUnknown_QueryInterface(device, &IID_IDirectInputDevice2W, (LPVOID*)&obj); 199 ok(SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice7W) failed: %08x\n", hr); 200 test_object_info(obj, data->hwnd); 201 if (obj) IUnknown_Release(obj); 202 203 IUnknown_Release(device); 204 } 205 return DIENUM_CONTINUE; 206 } 207 208 static void device_tests(void) 209 { 210 HRESULT hr; 211 IDirectInputA *pDI = NULL, *obj = NULL; 212 HINSTANCE hInstance = GetModuleHandleW(NULL); 213 HWND hwnd; 214 struct enum_data data; 215 216 hr = CoCreateInstance(&CLSID_DirectInput, 0, 1, &IID_IDirectInput2A, (LPVOID*)&pDI); 217 if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_DEVICENOTREG) 218 { 219 skip("Tests require a newer dinput version\n"); 220 return; 221 } 222 ok(SUCCEEDED(hr), "DirectInputCreateA() failed: %08x\n", hr); 223 if (FAILED(hr)) return; 224 225 hr = IDirectInput_Initialize(pDI, hInstance, DIRECTINPUT_VERSION); 226 ok(SUCCEEDED(hr), "Initialize() failed: %08x\n", hr); 227 if (FAILED(hr)) return; 228 229 hr = IUnknown_QueryInterface(pDI, &IID_IDirectInput2W, (LPVOID*)&obj); 230 ok(SUCCEEDED(hr), "QueryInterface(IDirectInput7W) failed: %08x\n", hr); 231 232 hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW, 10, 10, 200, 200, NULL, NULL, 233 NULL, NULL); 234 ok(hwnd != NULL, "err: %d\n", GetLastError()); 235 if (hwnd) 236 { 237 ShowWindow(hwnd, SW_SHOW); 238 239 data.pDI = pDI; 240 data.hwnd = hwnd; 241 hr = IDirectInput_EnumDevices(pDI, 0, enum_devices, &data, DIEDFL_ALLDEVICES); 242 ok(SUCCEEDED(hr), "IDirectInput_EnumDevices() failed: %08x\n", hr); 243 244 245 /* If GetDeviceStatus returns DI_OK the device must exist */ 246 hr = IDirectInput_GetDeviceStatus(pDI, &GUID_Joystick); 247 if (hr == DI_OK) 248 { 249 IDirectInputDeviceA *device = NULL; 250 251 hr = IDirectInput_CreateDevice(pDI, &GUID_Joystick, &device, NULL); 252 ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr); 253 if (device) IUnknown_Release(device); 254 } 255 256 DestroyWindow(hwnd); 257 } 258 if (obj) IUnknown_Release(obj); 259 if (pDI) IUnknown_Release(pDI); 260 } 261 262 START_TEST(device) 263 { 264 CoInitialize(NULL); 265 266 device_tests(); 267 268 CoUninitialize(); 269 } 270