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     IDirectInputDevice_Unacquire(pMouse);
156     cnt = 1;
157     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
158     ok(hr == S_OK && cnt > 0, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
159 
160     IDirectInputDevice_Acquire(pMouse);
161     mouse_event(MOUSEEVENTF_MOVE, 10, 10, 0, 0);
162     IDirectInputDevice_Unacquire(pMouse);
163     IDirectInputDevice_Acquire(pMouse);
164     cnt = 1;
165     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
166     ok(hr == S_OK && cnt > 0, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
167 
168     /* Check for buffer overflow */
169     for (i = 0; i < 6; i++)
170         mouse_event(MOUSEEVENTF_MOVE, 10 + i, 10 + i, 0, 0);
171 
172     cnt = 1;
173     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
174     ok(hr == DI_OK, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
175     cnt = 1;
176     hr = IDirectInputDevice_GetDeviceData(pMouse, sizeof(mouse_state), &mouse_state, &cnt, 0);
177     ok(hr == DI_OK && cnt == 1, "GetDeviceData() failed: %08x cnt:%d\n", hr, cnt);
178 
179     /* Check for granularity property using BYOFFSET */
180     memset(&di_op, 0, sizeof(di_op));
181     di_op.diph.dwHow = DIPH_BYOFFSET;
182     di_op.diph.dwObj = DIMOFS_Y;
183     di_op.diph.dwSize = sizeof(DIPROPDWORD);
184     di_op.diph.dwHeaderSize = sizeof(DIPROPHEADER);
185     hr = IDirectInputDevice_GetProperty(pMouse, DIPROP_GRANULARITY, &di_op.diph);
186     /* Granularity of Y axis should be 1! */
187     ok(hr == S_OK && di_op.dwData == 1, "GetProperty(): %08x, dwData: %i but should be 1.\n", hr, di_op.dwData);
188 
189     /* Check for granularity property using BYID */
190     memset(&di_op, 0, sizeof(di_op));
191     di_op.diph.dwHow = DIPH_BYID;
192     /* WINE_MOUSE_Y_AXIS_INSTANCE := 1 */
193     di_op.diph.dwObj = (DIDFT_MAKEINSTANCE(1) | DIDFT_RELAXIS);
194     di_op.diph.dwSize = sizeof(DIPROPDWORD);
195     di_op.diph.dwHeaderSize = sizeof(DIPROPHEADER);
196     hr = IDirectInputDevice_GetProperty(pMouse, DIPROP_GRANULARITY, &di_op.diph);
197     /* Granularity of Y axis should be 1! */
198     ok(hr == S_OK && di_op.dwData == 1, "GetProperty(): %08x, dwData: %i but should be 1.\n", hr, di_op.dwData);
199 }
200     if (pMouse) IUnknown_Release(pMouse);
201 
202     DestroyWindow( hwnd2 );
203 }
204 
205 static void mouse_tests(void)
206 {
207     HRESULT hr;
208     IDirectInputA *pDI = NULL;
209     HINSTANCE hInstance = GetModuleHandleW(NULL);
210     HWND hwnd;
211     ULONG ref = 0;
212 
213     hr = DirectInputCreateA(hInstance, DIRECTINPUT_VERSION, &pDI, NULL);
214     if (hr == DIERR_OLDDIRECTINPUTVERSION)
215     {
216         skip("Tests require a newer dinput version\n");
217         return;
218     }
219     ok(SUCCEEDED(hr), "DirectInputCreateA() failed: %08x\n", hr);
220     if (FAILED(hr)) return;
221 
222     hwnd = CreateWindowA("static", "Title", WS_OVERLAPPEDWINDOW, 10, 10, 200, 200, NULL, NULL,
223                          NULL, NULL);
224     ok(hwnd != NULL, "err: %d\n", GetLastError());
225     if (hwnd)
226     {
227         ShowWindow(hwnd, SW_SHOW);
228 
229         test_set_coop(pDI, hwnd);
230         test_acquire(pDI, hwnd);
231 
232         DestroyWindow(hwnd);
233     }
234     if (pDI) ref = IUnknown_Release(pDI);
235     ok(!ref, "IDirectInput_Release() reference count = %d\n", ref);
236 }
237 
238 START_TEST(mouse)
239 {
240     CoInitialize(NULL);
241 
242     mouse_tests();
243 
244     CoUninitialize();
245 }
246