1 /*
2  * Copyright (c) 2005 Robert Reif
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 0x0700
21 
22 #define COBJMACROS
23 #include <windows.h>
24 
25 #include <math.h>
26 #include <stdlib.h>
27 
28 #include "wine/test.h"
29 #include "windef.h"
30 #include "wingdi.h"
31 #include "dinput.h"
32 
33 static const HRESULT SetCoop_null_window[16] =  {
34     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG,
35     E_INVALIDARG, E_HANDLE,     E_HANDLE,     E_INVALIDARG,
36     E_INVALIDARG, E_HANDLE,     S_OK,         E_INVALIDARG,
37     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG};
38 
39 static const HRESULT SetCoop_real_window[16] =  {
40     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG,
41     E_INVALIDARG, S_OK,         S_OK,         E_INVALIDARG,
42     E_INVALIDARG, E_NOTIMPL,    S_OK,         E_INVALIDARG,
43     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG};
44 
45 static const HRESULT SetCoop_child_window[16] =  {
46     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG,
47     E_INVALIDARG, E_HANDLE,     E_HANDLE,     E_INVALIDARG,
48     E_INVALIDARG, E_HANDLE,     E_HANDLE,     E_INVALIDARG,
49     E_INVALIDARG, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG};
50 
51 static void test_set_coop(IDirectInputA *pDI, HWND hwnd)
52 {
53     HRESULT hr;
54     IDirectInputDeviceA *pMouse = NULL;
55     int i;
56     HWND child;
57 
58     hr = IDirectInput_CreateDevice(pDI, &GUID_SysMouse, &pMouse, NULL);
59     ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
60     if (FAILED(hr)) return;
61 
62     for (i=0; i<16; i++)
63     {
64         hr = IDirectInputDevice_SetCooperativeLevel(pMouse, NULL, i);
65         ok(hr == SetCoop_null_window[i], "SetCooperativeLevel(NULL, %d): %08x\n", i, hr);
66     }
67     for (i=0; i<16; i++)
68     {
69         hr = IDirectInputDevice_SetCooperativeLevel(pMouse, hwnd, i);
70         ok(hr == SetCoop_real_window[i], "SetCooperativeLevel(hwnd, %d): %08x\n", i, hr);
71     }
72 
73     child = CreateWindowA("static", "Title", WS_CHILD | WS_VISIBLE, 10, 10, 50, 50, hwnd, NULL,
74                           NULL, NULL);
75     ok(child != NULL, "err: %d\n", GetLastError());
76 
77     for (i=0; i<16; i++)
78     {
79         hr = IDirectInputDevice_SetCooperativeLevel(pMouse, child, i);
80         ok(hr == SetCoop_child_window[i], "SetCooperativeLevel(child, %d): %08x\n", i, hr);
81     }
82 
83     DestroyWindow(child);
84     if (pMouse) IUnknown_Release(pMouse);
85 }
86 
87 static void test_acquire(IDirectInputA *pDI, HWND hwnd)
88 {
89     HRESULT hr;
90     IDirectInputDeviceA *pMouse = NULL;
91     DIMOUSESTATE m_state;
92     HWND hwnd2;
93     DIPROPDWORD di_op;
94     DIDEVICEOBJECTDATA mouse_state;
95     DWORD cnt;
96     int i;
97 
98     if (! SetForegroundWindow(hwnd))
99     {
100         skip("Not running as foreground app, skipping acquire tests\n");
101         return;
102     }
103 
104     hr = IDirectInput_CreateDevice(pDI, &GUID_SysMouse, &pMouse, NULL);
105     ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
106     if (FAILED(hr)) return;
107 
108     hr = IDirectInputDevice_SetCooperativeLevel(pMouse, hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
109     ok(hr == S_OK, "SetCooperativeLevel: %08x\n", hr);
110 
111     memset(&di_op, 0, sizeof(di_op));
112     di_op.dwData = 5;
113     di_op.diph.dwHow = DIPH_DEVICE;
114     di_op.diph.dwSize = sizeof(DIPROPDWORD);
115     di_op.diph.dwHeaderSize = sizeof(DIPROPHEADER);
116     hr = IDirectInputDevice_SetProperty(pMouse, DIPROP_BUFFERSIZE, (LPCDIPROPHEADER)&di_op);
117     ok(hr == S_OK, "SetProperty() failed: %08x\n", hr);
118 
119     hr = IDirectInputDevice_SetDataFormat(pMouse, &c_dfDIMouse);
120     ok(SUCCEEDED(hr), "IDirectInputDevice_SetDataFormat() failed: %08x\n", hr);
121     hr = IDirectInputDevice_Unacquire(pMouse);
122     ok(hr == S_FALSE, "IDirectInputDevice_Unacquire() should have failed: %08x\n", hr);
123     hr = IDirectInputDevice_Acquire(pMouse);
124     ok(SUCCEEDED(hr), "IDirectInputDevice_Acquire() failed: %08x\n", hr);
125     hr = IDirectInputDevice_Acquire(pMouse);
126     ok(hr == S_FALSE, "IDirectInputDevice_Acquire() should have failed: %08x\n", hr);
127 
128     /* Foreground coop level requires window to have focus */
129     /* Create a temporary window, this should make dinput
130      * lose mouse input */
131     hwnd2 = CreateWindowA("static", "Temporary", WS_VISIBLE, 10, 210, 200, 200, NULL, NULL, NULL,
132                           NULL);
133     ok(hwnd2 != NULL, "CreateWindowA failed with %u\n", GetLastError());
134 
135     hr = IDirectInputDevice_GetDeviceState(pMouse, sizeof(m_state), &m_state);
136     ok(hr == DIERR_NOTACQUIRED, "GetDeviceState() should have failed: %08x\n", hr);
137 
138     hr = IDirectInputDevice_Acquire(pMouse);
139     ok(hr == DIERR_OTHERAPPHASPRIO, "Acquire() should have failed: %08x\n", hr);
140 
141     SetActiveWindow( hwnd );
142     hr = IDirectInputDevice_Acquire(pMouse);
143     ok(hr == S_OK, "Acquire() failed: %08x\n", hr);
144 
145 if (!winetest_interactive)
146     skip("ROSTESTS-176/CORE-9710: Skipping randomly failing tests\n");
147 else {
148 
149     mouse_event(MOUSEEVENTF_MOVE, 10, 10, 0, 0);
150     cnt = 1;
151     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
152     ok(hr == S_OK && cnt > 0, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
153 
154     mouse_event(MOUSEEVENTF_MOVE, 10, 10, 0, 0);
155     hr = IDirectInputDevice_Unacquire(pMouse);
156     ok(hr == S_OK, "Failed: %08x\n", hr);
157     cnt = 1;
158     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
159     ok(hr == S_OK && cnt > 0, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
160 
161     hr = IDirectInputDevice_Acquire(pMouse);
162     ok(hr == S_OK, "Failed: %08x\n", hr);
163     mouse_event(MOUSEEVENTF_MOVE, 10, 10, 0, 0);
164     hr = IDirectInputDevice_Unacquire(pMouse);
165     ok(hr == S_OK, "Failed: %08x\n", hr);
166 
167     hr = IDirectInputDevice_Acquire(pMouse);
168     ok(hr == S_OK, "Failed: %08x\n", hr);
169     cnt = 1;
170     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
171     ok(hr == S_OK && cnt > 0, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
172 
173     /* Check for buffer overflow */
174     for (i = 0; i < 6; i++)
175         mouse_event(MOUSEEVENTF_MOVE, 10 + i, 10 + i, 0, 0);
176 
177     cnt = 1;
178     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
179     ok(hr == DI_OK, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
180     cnt = 1;
181     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
182     ok(hr == DI_OK && cnt == 1, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
183 
184     /* Check for granularity property using BYOFFSET */
185     memset(&di_op, 0, sizeof(di_op));
186     di_op.diph.dwHow = DIPH_BYOFFSET;
187     di_op.diph.dwObj = DIMOFS_Y;
188     di_op.diph.dwSize = sizeof(DIPROPDWORD);
189     di_op.diph.dwHeaderSize = sizeof(DIPROPHEADER);
190     hr = IDirectInputDevice_GetProperty(pMouse, DIPROP_GRANULARITY, &di_op.diph);
191     /* Granularity of Y axis should be 1! */
192     ok(hr == S_OK && di_op.dwData == 1, "GetProperty(): %08x, dwData: %i but should be 1.\n", hr, di_op.dwData);
193 
194     /* Check for granularity property using BYID */
195     memset(&di_op, 0, sizeof(di_op));
196     di_op.diph.dwHow = DIPH_BYID;
197     /* WINE_MOUSE_Y_AXIS_INSTANCE := 1 */
198     di_op.diph.dwObj = (DIDFT_MAKEINSTANCE(1) | DIDFT_RELAXIS);
199     di_op.diph.dwSize = sizeof(DIPROPDWORD);
200     di_op.diph.dwHeaderSize = sizeof(DIPROPHEADER);
201     hr = IDirectInputDevice_GetProperty(pMouse, DIPROP_GRANULARITY, &di_op.diph);
202     /* Granularity of Y axis should be 1! */
203     ok(hr == S_OK && di_op.dwData == 1, "GetProperty(): %08x, dwData: %i but should be 1.\n", hr, di_op.dwData);
204 }
205     if (pMouse) IUnknown_Release(pMouse);
206 
207     DestroyWindow( hwnd2 );
208 }
209 
210 static void test_GetDeviceInfo(IDirectInputA *pDI)
211 {
212     HRESULT hr;
213     IDirectInputDeviceA *pMouse = NULL;
214     DIDEVICEINSTANCEA instA;
215     DIDEVICEINSTANCE_DX3A inst3A;
216 
217     hr = IDirectInput_CreateDevice(pDI, &GUID_SysMouse, &pMouse, NULL);
218     ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
219     if (FAILED(hr)) return;
220 
221     instA.dwSize = sizeof(instA);
222     hr = IDirectInputDevice_GetDeviceInfo(pMouse, &instA);
223     ok(SUCCEEDED(hr), "got %08x\n", hr);
224 
225     inst3A.dwSize = sizeof(inst3A);
226     hr = IDirectInputDevice_GetDeviceInfo(pMouse, (DIDEVICEINSTANCEA *)&inst3A);
227     ok(SUCCEEDED(hr), "got %08x\n", hr);
228 
229     ok(instA.dwSize != inst3A.dwSize, "got %d, %d \n", instA.dwSize, inst3A.dwSize);
230     ok(IsEqualGUID(&instA.guidInstance, &inst3A.guidInstance), "got %s, %s\n",
231             wine_dbgstr_guid(&instA.guidInstance), wine_dbgstr_guid(&inst3A.guidInstance) );
232     ok(IsEqualGUID(&instA.guidProduct, &inst3A.guidProduct), "got %s, %s\n",
233             wine_dbgstr_guid(&instA.guidProduct), wine_dbgstr_guid(&inst3A.guidProduct) );
234     ok(instA.dwDevType == inst3A.dwDevType, "got %d, %d\n", instA.dwDevType, inst3A.dwDevType);
235 
236     IUnknown_Release(pMouse);
237 }
238 
239 static BOOL CALLBACK EnumAxes(const DIDEVICEOBJECTINSTANCEA *pdidoi, void *pContext)
240 {
241     if (IsEqualIID(&pdidoi->guidType, &GUID_XAxis) ||
242         IsEqualIID(&pdidoi->guidType, &GUID_YAxis) ||
243         IsEqualIID(&pdidoi->guidType, &GUID_ZAxis))
244     {
245         ok(pdidoi->dwFlags & DIDOI_ASPECTPOSITION, "Missing DIDOI_ASPECTPOSITION, flags are 0x%x\n",
246             pdidoi->dwFlags);
247     }
248     else
249         ok(pdidoi->dwFlags == 0, "Flags are 0x%x\n", pdidoi->dwFlags);
250 
251     return DIENUM_CONTINUE;
252 }
253 
254 static void test_mouse_EnumObjects(IDirectInputA *pDI)
255 {
256     HRESULT hr;
257     IDirectInputDeviceA *pMouse = NULL;
258 
259     hr = IDirectInput_CreateDevice(pDI, &GUID_SysMouse, &pMouse, NULL);
260     ok(SUCCEEDED(hr), "IDirectInput_CreateDevice() failed: %08x\n", hr);
261     if (FAILED(hr)) return;
262 
263     hr = IDirectInputDevice_EnumObjects(pMouse, EnumAxes, NULL, DIDFT_ALL);
264     ok(hr==DI_OK,"IDirectInputDevice_EnumObjects() failed: %08x\n", hr);
265 
266     if (pMouse) IUnknown_Release(pMouse);
267 }
268 
269 static void mouse_tests(void)
270 {
271     HRESULT hr;
272     IDirectInputA *pDI = NULL;
273     HINSTANCE hInstance = GetModuleHandleW(NULL);
274     HWND hwnd;
275     ULONG ref = 0;
276 
277     hr = DirectInputCreateA(hInstance, DIRECTINPUT_VERSION, &pDI, NULL);
278     if (hr == DIERR_OLDDIRECTINPUTVERSION)
279     {
280         skip("Tests require a newer dinput version\n");
281         return;
282     }
283     ok(SUCCEEDED(hr), "DirectInputCreateA() failed: %08x\n", hr);
284     if (FAILED(hr)) return;
285 
286     hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW, 10, 10, 200, 200, NULL, NULL,
287                          NULL, NULL);
288     ok(hwnd != NULL, "err: %d\n", GetLastError());
289     if (hwnd)
290     {
291         ShowWindow(hwnd, SW_SHOW);
292 
293         test_set_coop(pDI, hwnd);
294         test_acquire(pDI, hwnd);
295         test_GetDeviceInfo(pDI);
296         test_mouse_EnumObjects(pDI);
297 
298         DestroyWindow(hwnd);
299     }
300     if (pDI) ref = IUnknown_Release(pDI);
301     ok(!ref, "IDirectInput_Release() reference count = %d\n", ref);
302 }
303 
304 START_TEST(mouse)
305 {
306     CoInitialize(NULL);
307 
308     mouse_tests();
309 
310     CoUninitialize();
311 }
312