359 lines
16 KiB
C
359 lines
16 KiB
C
/*
|
|
* Copyright (c) 2006 Vitaliy Margolen
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#define DIRECTINPUT_VERSION 0x0700
|
|
|
|
#define COBJMACROS
|
|
#include <windows.h>
|
|
|
|
#include "wine/test.h"
|
|
#include "windef.h"
|
|
#include "dinput.h"
|
|
|
|
#include <limits.h>
|
|
|
|
static const DIOBJECTDATAFORMAT obj_data_format[] = {
|
|
{ &GUID_YAxis, 16, DIDFT_OPTIONAL|DIDFT_AXIS |DIDFT_MAKEINSTANCE(1), 0},
|
|
{ &GUID_Button,15, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(3), 0},
|
|
{ &GUID_Key, 0, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(16),0},
|
|
{ &GUID_Key, 1, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(17),0},
|
|
{ &GUID_Key, 2, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(18),0},
|
|
{ &GUID_Key, 3, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(19),0},
|
|
{ &GUID_Key, 4, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(20),0},
|
|
{ &GUID_Key, 5, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(21),0},
|
|
{ &GUID_Key, 6, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(22),0},
|
|
{ &GUID_Key, 7, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(23),0},
|
|
{ &GUID_Key, 8, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(24),0},
|
|
{ &GUID_Key, 9, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(25),0},
|
|
{ &GUID_Key, 10, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(26),0},
|
|
{ &GUID_Key, 11, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(27),0},
|
|
{ &GUID_Key, 12, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(28),0},
|
|
{ NULL, 13, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(5),0},
|
|
|
|
{ &GUID_Button,14, DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_MAKEINSTANCE(32),0}
|
|
};
|
|
|
|
static const DIDATAFORMAT data_format = {
|
|
sizeof(DIDATAFORMAT),
|
|
sizeof(DIOBJECTDATAFORMAT),
|
|
DIDF_ABSAXIS,
|
|
32,
|
|
ARRAY_SIZE(obj_data_format),
|
|
(LPDIOBJECTDATAFORMAT)obj_data_format
|
|
};
|
|
|
|
static BOOL CALLBACK enum_callback(const DIDEVICEOBJECTINSTANCEA *oi, void *info)
|
|
{
|
|
if (winetest_debug > 1)
|
|
trace(" Type:%4x Ofs:%3d Flags:%08x Name:%s\n",
|
|
oi->dwType, oi->dwOfs, oi->dwFlags, oi->tszName);
|
|
(*(int*)info)++;
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
static BOOL CALLBACK enum_type_callback(const DIDEVICEOBJECTINSTANCEA *oi, void *info)
|
|
{
|
|
DWORD expected = *(DWORD*)info;
|
|
ok (expected & DIDFT_GETTYPE(oi->dwType), "EnumObjects() enumerated wrong type for obj %s, expected: %08x got: %08x\n", oi->tszName, expected, oi->dwType);
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
static void test_object_info(IDirectInputDeviceA *device, HWND hwnd)
|
|
{
|
|
HRESULT hr;
|
|
DIPROPDWORD dp;
|
|
DIDEVICEOBJECTINSTANCEA obj_info;
|
|
DWORD obj_types[] = {DIDFT_BUTTON, DIDFT_AXIS, DIDFT_POV};
|
|
int type_index;
|
|
int cnt1 = 0;
|
|
DWORD cnt = 0;
|
|
DIDEVICEOBJECTDATA buffer[5];
|
|
|
|
hr = IDirectInputDevice_EnumObjects(device, NULL, &cnt, DIDFT_ALL);
|
|
ok(hr == DIERR_INVALIDPARAM, "IDirectInputDevice_EnumObjects returned %08x, expected %08x\n", hr, DIERR_INVALIDPARAM);
|
|
|
|
hr = IDirectInputDevice_EnumObjects(device, enum_callback, &cnt, DIDFT_ALL);
|
|
ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr);
|
|
|
|
hr = IDirectInputDevice_SetDataFormat(device, &data_format);
|
|
ok(SUCCEEDED(hr), "SetDataFormat() failed: %08x\n", hr);
|
|
|
|
hr = IDirectInputDevice_EnumObjects(device, enum_callback, &cnt1, DIDFT_ALL);
|
|
ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr);
|
|
if (0) /* fails for joystick only */
|
|
ok(cnt == cnt1, "Enum count changed from %d to %d\n", cnt, cnt1);
|
|
|
|
/* Testing EnumObjects with different types of device objects */
|
|
for (type_index=0; type_index < ARRAY_SIZE(obj_types); type_index++)
|
|
{
|
|
hr = IDirectInputDevice_EnumObjects(device, enum_type_callback, &obj_types[type_index], obj_types[type_index]);
|
|
ok(SUCCEEDED(hr), "EnumObjects() failed: %08x\n", hr);
|
|
}
|
|
|
|
/* Test buffered mode */
|
|
memset(&dp, 0, sizeof(dp));
|
|
dp.diph.dwSize = sizeof(DIPROPDWORD);
|
|
dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
dp.diph.dwHow = DIPH_DEVICE;
|
|
dp.diph.dwObj = 0;
|
|
dp.dwData = UINT_MAX;
|
|
|
|
hr = IDirectInputDevice_GetProperty(device, DIPROP_BUFFERSIZE, &dp.diph);
|
|
ok(hr == DI_OK, "Failed: %08x\n", hr);
|
|
ok(dp.dwData == 0, "got %d\n", dp.dwData);
|
|
|
|
dp.dwData = UINT_MAX;
|
|
hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
|
|
ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
|
|
|
|
dp.dwData = 0;
|
|
hr = IDirectInputDevice_GetProperty(device, DIPROP_BUFFERSIZE, &dp.diph);
|
|
ok(hr == DI_OK, "Failed: %08x\n", hr);
|
|
ok(dp.dwData == UINT_MAX, "got %d\n", dp.dwData);
|
|
|
|
dp.dwData = 0;
|
|
hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
|
|
ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
|
|
cnt = 5;
|
|
hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0);
|
|
ok(hr == DI_OK && cnt == 5, "GetDeviceData() failed: %08x cnt: %d\n", hr, cnt);
|
|
hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0);
|
|
ok(hr == DIERR_NOTBUFFERED, "GetDeviceData() should have failed: %08x\n", hr);
|
|
IDirectInputDevice_Acquire(device);
|
|
hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0);
|
|
ok(hr == DIERR_NOTBUFFERED, "GetDeviceData() should have failed: %08x\n", hr);
|
|
IDirectInputDevice_Unacquire(device);
|
|
|
|
dp.dwData = 20;
|
|
hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
|
|
ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
|
|
cnt = 5;
|
|
hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0);
|
|
ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr);
|
|
hr = IDirectInputDevice_GetDeviceData(device, sizeof(DIDEVICEOBJECTDATA_DX3), buffer, &cnt, 0);
|
|
ok(hr == DIERR_NOTACQUIRED, "GetDeviceData() should have failed: %08x\n", hr);
|
|
hr = IDirectInputDevice_Acquire(device);
|
|
ok(hr == DI_OK, "Acquire() failed: %08x\n", hr);
|
|
cnt = 1;
|
|
hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0);
|
|
ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr);
|
|
hr = IDirectInputDevice_Unacquire(device);
|
|
ok(hr == DI_OK, "Unacquire() failed: %08x\n", hr);
|
|
cnt = 1;
|
|
hr = IDirectInputDevice_GetDeviceData(device, sizeof(buffer[0]), buffer, &cnt, 0);
|
|
ok(hr == DI_OK, "GetDeviceData() failed: %08x\n", hr);
|
|
|
|
hr = IDirectInputDevice_GetObjectInfo(device, NULL, 16, DIPH_BYOFFSET);
|
|
ok(hr == E_POINTER, "IDirectInputDevice_GetObjectInfo returned %08x, expected %08x\n", hr, E_POINTER);
|
|
|
|
obj_info.dwSize = 1;
|
|
hr = IDirectInputDevice_GetObjectInfo(device, &obj_info, 16, DIPH_BYOFFSET);
|
|
ok(hr == DIERR_INVALIDPARAM, "IDirectInputDevice_GetObjectInfo returned %08x, expected %08x\n", hr, DIERR_INVALIDPARAM);
|
|
obj_info.dwSize = 0xdeadbeef;
|
|
hr = IDirectInputDevice_GetObjectInfo(device, &obj_info, 16, DIPH_BYOFFSET);
|
|
ok(hr == DIERR_INVALIDPARAM, "IDirectInputDevice_GetObjectInfo returned %08x, expected %08x\n", hr, DIERR_INVALIDPARAM);
|
|
|
|
/* No need to test devices without axis */
|
|
obj_info.dwSize = sizeof(obj_info);
|
|
hr = IDirectInputDevice_GetObjectInfo(device, &obj_info, 16, DIPH_BYOFFSET);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
/* No device supports per axis relative/absolute mode */
|
|
dp.diph.dwHow = DIPH_BYOFFSET;
|
|
dp.diph.dwObj = 16;
|
|
dp.dwData = DIPROPAXISMODE_ABS;
|
|
hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph);
|
|
ok(hr == DIERR_UNSUPPORTED, "SetProperty() returned: %08x\n", hr);
|
|
dp.diph.dwHow = DIPH_DEVICE;
|
|
hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph);
|
|
ok(hr == DIERR_INVALIDPARAM, "SetProperty() returned: %08x\n", hr);
|
|
dp.diph.dwObj = 0;
|
|
hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph);
|
|
ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
|
|
|
|
/* Cannot change mode while acquired */
|
|
hr = IDirectInputDevice_Acquire(device);
|
|
ok(hr == DI_OK, "Acquire() failed: %08x\n", hr);
|
|
|
|
hr = IDirectInputDevice_SetProperty(device, DIPROP_AXISMODE, &dp.diph);
|
|
ok(hr == DIERR_ACQUIRED, "SetProperty() returned: %08x\n", hr);
|
|
hr = IDirectInputDevice_Unacquire(device);
|
|
ok(hr == DI_OK, "Unacquire() failed: %08x\n", hr);
|
|
}
|
|
|
|
/* Reset buffer size */
|
|
dp.diph.dwSize = sizeof(DIPROPDWORD);
|
|
dp.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
|
dp.diph.dwHow = DIPH_DEVICE;
|
|
dp.diph.dwObj = 0;
|
|
dp.dwData = 0;
|
|
hr = IDirectInputDevice_SetProperty(device, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&dp.diph);
|
|
ok(hr == DI_OK, "SetProperty() failed: %08x\n", hr);
|
|
}
|
|
|
|
struct enum_data
|
|
{
|
|
IDirectInputA *pDI;
|
|
HWND hwnd;
|
|
BOOL tested_product_creation;
|
|
};
|
|
|
|
static BOOL CALLBACK enum_devices(const DIDEVICEINSTANCEA *lpddi, void *pvRef)
|
|
{
|
|
struct enum_data *data = pvRef;
|
|
IDirectInputDeviceA *device, *obj = NULL;
|
|
DIDEVICEINSTANCEA ddi2;
|
|
HRESULT hr;
|
|
IUnknown *iface, *tmp_iface;
|
|
|
|
hr = IDirectInput_GetDeviceStatus(data->pDI, &lpddi->guidInstance);
|
|
ok(hr == DI_OK, "IDirectInput_GetDeviceStatus() failed: %08x\n", hr);
|
|
|
|
if (hr == DI_OK)
|
|
{
|
|
hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidInstance, &device, NULL);
|
|
ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
|
|
trace("Testing device %p \"%s\"\n", device, lpddi->tszInstanceName);
|
|
|
|
hr = IUnknown_QueryInterface(device, &IID_IDirectInputDevice2A, (LPVOID*)&obj);
|
|
ok(SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice2A) failed: %08x\n", hr);
|
|
test_object_info(obj, data->hwnd);
|
|
IUnknown_Release(obj);
|
|
obj = NULL;
|
|
|
|
hr = IUnknown_QueryInterface(device, &IID_IDirectInputDevice2W, (LPVOID*)&obj);
|
|
ok(SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice2W) failed: %08x\n", hr);
|
|
test_object_info(obj, data->hwnd);
|
|
IUnknown_Release(obj);
|
|
|
|
hr = IUnknown_QueryInterface( device, &IID_IDirectInputDeviceA, (void **)&iface );
|
|
ok( SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDeviceA) failed: %08x\n", hr );
|
|
hr = IUnknown_QueryInterface( device, &IID_IDirectInputDevice2A, (void **)&tmp_iface );
|
|
ok( SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice2A) failed: %08x\n", hr );
|
|
ok( tmp_iface == iface, "IDirectInputDevice2A iface differs from IDirectInputDeviceA\n" );
|
|
IUnknown_Release( tmp_iface );
|
|
hr = IUnknown_QueryInterface( device, &IID_IDirectInputDevice7A, (void **)&tmp_iface );
|
|
ok( SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice7A) failed: %08x\n", hr );
|
|
ok( tmp_iface == iface, "IDirectInputDevice7A iface differs from IDirectInputDeviceA\n" );
|
|
IUnknown_Release( tmp_iface );
|
|
IUnknown_Release( iface );
|
|
|
|
hr = IUnknown_QueryInterface( device, &IID_IUnknown, (void **)&iface );
|
|
ok( SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IUnknown) failed: %08x\n", hr );
|
|
hr = IUnknown_QueryInterface( device, &IID_IDirectInputDeviceW, (void **)&tmp_iface );
|
|
ok( SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDeviceW) failed: %08x\n", hr );
|
|
ok( tmp_iface == iface, "IDirectInputDeviceW iface differs from IUnknown\n" );
|
|
IUnknown_Release( tmp_iface );
|
|
hr = IUnknown_QueryInterface( device, &IID_IDirectInputDevice2W, (void **)&tmp_iface );
|
|
ok( SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice2W) failed: %08x\n", hr );
|
|
ok( tmp_iface == iface, "IDirectInputDevice2W iface differs from IUnknown\n" );
|
|
IUnknown_Release( tmp_iface );
|
|
hr = IUnknown_QueryInterface( device, &IID_IDirectInputDevice7W, (void **)&tmp_iface );
|
|
ok( SUCCEEDED(hr), "IUnknown_QueryInterface(IID_IDirectInputDevice7W) failed: %08x\n", hr );
|
|
ok( tmp_iface == iface, "IDirectInputDevice7W iface differs from IUnknown\n" );
|
|
IUnknown_Release( tmp_iface );
|
|
IUnknown_Release( iface );
|
|
|
|
IUnknown_Release(device);
|
|
|
|
if (!IsEqualGUID(&lpddi->guidInstance, &lpddi->guidProduct))
|
|
{
|
|
data->tested_product_creation = TRUE;
|
|
hr = IDirectInput_CreateDevice(data->pDI, &lpddi->guidProduct, &device, NULL);
|
|
ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
|
|
|
|
ddi2.dwSize = sizeof(ddi2);
|
|
hr = IDirectInputDevice_GetDeviceInfo(device, &ddi2);
|
|
ok(SUCCEEDED(hr), "IDirectInput_GetDeviceInfo failed: %08x\n", hr);
|
|
|
|
ok(IsEqualGUID(&lpddi->guidProduct, &ddi2.guidProduct), "Product GUIDs do not match. Expected %s, got %s\n", debugstr_guid(&lpddi->guidProduct), debugstr_guid(&ddi2.guidProduct));
|
|
ok(IsEqualGUID(&ddi2.guidProduct, &ddi2.guidInstance), "Instance GUID should equal product GUID. Expected %s, got %s\n", debugstr_guid(&ddi2.guidProduct), debugstr_guid(&ddi2.guidInstance));
|
|
/* we cannot compare guidInstances as we may get a different device */
|
|
|
|
IUnknown_Release(device);
|
|
}
|
|
|
|
}
|
|
return DIENUM_CONTINUE;
|
|
}
|
|
|
|
static void device_tests(void)
|
|
{
|
|
HRESULT hr;
|
|
IDirectInputA *pDI = NULL, *obj = NULL;
|
|
HINSTANCE hInstance = GetModuleHandleW(NULL);
|
|
HWND hwnd;
|
|
struct enum_data data;
|
|
|
|
hr = CoCreateInstance(&CLSID_DirectInput, 0, 1, &IID_IDirectInput2A, (LPVOID*)&pDI);
|
|
if (hr == DIERR_OLDDIRECTINPUTVERSION || hr == DIERR_DEVICENOTREG)
|
|
{
|
|
skip("Tests require a newer dinput version\n");
|
|
return;
|
|
}
|
|
ok(SUCCEEDED(hr), "DirectInputCreateA() failed: %08x\n", hr);
|
|
if (FAILED(hr)) return;
|
|
|
|
hr = IDirectInput_Initialize(pDI, hInstance, DIRECTINPUT_VERSION);
|
|
ok(SUCCEEDED(hr), "Initialize() failed: %08x\n", hr);
|
|
if (FAILED(hr)) return;
|
|
|
|
hr = IUnknown_QueryInterface(pDI, &IID_IDirectInput2W, (LPVOID*)&obj);
|
|
ok(SUCCEEDED(hr), "QueryInterface(IDirectInput7W) failed: %08x\n", hr);
|
|
|
|
hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW, 10, 10, 200, 200, NULL, NULL,
|
|
NULL, NULL);
|
|
ok(hwnd != NULL, "err: %d\n", GetLastError());
|
|
if (hwnd)
|
|
{
|
|
ShowWindow(hwnd, SW_SHOW);
|
|
|
|
data.pDI = pDI;
|
|
data.hwnd = hwnd;
|
|
data.tested_product_creation = FALSE;
|
|
hr = IDirectInput_EnumDevices(pDI, 0, enum_devices, &data, DIEDFL_ALLDEVICES);
|
|
ok(SUCCEEDED(hr), "IDirectInput_EnumDevices() failed: %08x\n", hr);
|
|
|
|
if (!data.tested_product_creation) winetest_skip("Device creation using product GUID not tested\n");
|
|
|
|
/* If GetDeviceStatus returns DI_OK the device must exist */
|
|
hr = IDirectInput_GetDeviceStatus(pDI, &GUID_Joystick);
|
|
if (hr == DI_OK)
|
|
{
|
|
IDirectInputDeviceA *device = NULL;
|
|
|
|
hr = IDirectInput_CreateDevice(pDI, &GUID_Joystick, &device, NULL);
|
|
ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
|
|
if (device) IUnknown_Release(device);
|
|
}
|
|
|
|
DestroyWindow(hwnd);
|
|
}
|
|
if (obj) IUnknown_Release(obj);
|
|
if (pDI) IUnknown_Release(pDI);
|
|
}
|
|
|
|
START_TEST(device)
|
|
{
|
|
CoInitialize(NULL);
|
|
|
|
device_tests();
|
|
|
|
CoUninitialize();
|
|
}
|