1 /* 2 * Unit tests for joystick APIs 3 * 4 * Copyright 2014 Bruno Jesus 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 23 #include "windef.h" 24 #include "winbase.h" 25 #include "winuser.h" 26 #include "mmsystem.h" 27 #include "wine/test.h" 28 29 static HWND window; 30 31 static LRESULT CALLBACK proc_window(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 32 { 33 return DefWindowProcA(hwnd, msg, wparam, lparam); 34 } 35 36 static void create_window(void) 37 { 38 const char name[] = "Joystick Test"; 39 WNDCLASSA wc; 40 41 memset(&wc, 0, sizeof(wc)); 42 wc.lpfnWndProc = proc_window; 43 wc.hInstance = 0; 44 wc.lpszClassName = name; 45 RegisterClassA(&wc); 46 window = CreateWindowExA(0, name, name, WS_OVERLAPPEDWINDOW, 47 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 48 NULL, NULL, NULL, NULL); 49 ok(window != NULL, "Expected CreateWindowEx to work, error %d\n", GetLastError()); 50 } 51 52 static void destroy_window(void) 53 { 54 DestroyWindow(window); 55 window = NULL; 56 } 57 58 static void test_api(void) 59 { 60 MMRESULT ret; 61 JOYCAPSA jc; 62 JOYCAPSW jcw; 63 JOYINFO info; 64 union _infoex 65 { 66 JOYINFOEX ex; 67 char buffer[sizeof(JOYINFOEX) * 2]; 68 } infoex; 69 UINT i, par, devices, joyid, win98 = 0, win8 = 0; 70 UINT period[] = {0, 1, 9, 10, 100, 1000, 1001, 10000, 65535, 65536, 0xFFFFFFFF}; 71 UINT threshold_error = 0x600, period_win8_error = 0x7CE; 72 UINT flags[] = { JOY_RETURNALL, JOY_RETURNBUTTONS, JOY_RETURNCENTERED, JOY_RETURNPOV, 73 JOY_RETURNPOVCTS, JOY_RETURNR, JOY_RETURNRAWDATA, JOY_RETURNU, 74 JOY_RETURNV, JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ }; 75 76 devices = joyGetNumDevs(); 77 joyid = -1; 78 /* joyGetNumDevs does NOT return the number of joysticks connected, only slots in the OS */ 79 for (i = 0; i < devices; i++) 80 { 81 memset(&jc, 0, sizeof(jc)); 82 ret = joyGetDevCapsA(JOYSTICKID1 + i, &jc, sizeof(jc)); 83 if (ret == JOYERR_NOERROR) 84 { 85 if (joyid == -1) /* Cache the first found joystick to run advanced tests below */ 86 joyid = JOYSTICKID1 + i; 87 88 trace("Joystick[%d] - name: '%s', axes: %d, buttons: %d, period range: %d - %d\n", 89 JOYSTICKID1 + i, jc.szPname, jc.wNumAxes, jc.wNumButtons, jc.wPeriodMin, jc.wPeriodMax); 90 ret = joyGetDevCapsW(JOYSTICKID1 + i, &jcw, sizeof(jcw)); 91 if (ret != MMSYSERR_NOTSUPPORTED) /* Win 98 */ 92 { 93 ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); 94 ok(jc.wNumAxes == jcw.wNumAxes, "Expected %d == %d\n", jc.wNumAxes, jcw.wNumAxes); 95 ok(jc.wNumButtons == jcw.wNumButtons, "Expected %d == %d\n", jc.wNumButtons, jcw.wNumButtons); 96 } 97 else win98++; 98 } 99 else 100 { 101 ok(ret == JOYERR_PARMS, "Expected %d, got %d\n", JOYERR_PARMS, ret); 102 ret = joyGetDevCapsW(JOYSTICKID1 + i, &jcw, sizeof(jcw)); 103 ok(ret == JOYERR_PARMS || (ret == MMSYSERR_NOTSUPPORTED) /* Win 98 */, 104 "Expected %d, got %d\n", JOYERR_PARMS, ret); 105 } 106 } 107 /* Test invalid joystick - If no joystick is present the driver is not initialized, 108 * so a NODRIVER error is returned, if at least one joystick is present the error is 109 * about invalid parameters. */ 110 ret = joyGetDevCapsA(joyid + devices, &jc, sizeof(jc)); 111 ok(ret == MMSYSERR_NODRIVER || ret == JOYERR_PARMS, 112 "Expected %d or %d, got %d\n", MMSYSERR_NODRIVER, JOYERR_PARMS, ret); 113 114 if (joyid == -1) 115 { 116 skip("This test requires a real joystick.\n"); 117 return; 118 } 119 120 /* Capture tests */ 121 ret = joySetCapture(NULL, joyid, 100, FALSE); 122 ok(ret == JOYERR_PARMS || broken(win98 && ret == MMSYSERR_INVALPARAM) /* Win 98 */, 123 "Expected %d, got %d\n", JOYERR_PARMS, ret); 124 ret = joySetCapture(window, joyid, 100, FALSE); 125 ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); 126 ret = joySetCapture(window, joyid, 100, FALSE); /* double capture */ 127 if (ret == JOYERR_NOCANDO) 128 { 129 todo_wine 130 ok(broken(1), "Expected double capture using joySetCapture to work\n"); 131 if (!win98 && broken(1)) win8++; /* Windows 98 or 8 cannot cope with that */ 132 } 133 else ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); 134 ret = joyReleaseCapture(joyid); 135 ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); 136 ret = joyReleaseCapture(joyid); 137 ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); /* double release */ 138 139 /* Try some unusual period values for joySetCapture and unusual threshold values for joySetThreshold. 140 * Windows XP allows almost all test values, Windows 8 will return error on most test values, Windows 141 * 98 allows anything but cuts the values to their maximum supported values internally. */ 142 for (i = 0; i < sizeof(period) / sizeof(period[0]); i++) 143 { 144 ret = joySetCapture(window, joyid, period[i], FALSE); 145 if (win8 && ((1 << i) & period_win8_error)) 146 ok(ret == JOYERR_NOCANDO, "Test [%d]: Expected %d, got %d\n", i, JOYERR_NOCANDO, ret); 147 else 148 ok(ret == JOYERR_NOERROR, "Test [%d]: Expected %d, got %d\n", i, JOYERR_NOERROR, ret); 149 ret = joyReleaseCapture(joyid); 150 ok(ret == JOYERR_NOERROR, "Test [%d]: Expected %d, got %d\n", i, JOYERR_NOERROR, ret); 151 /* Reuse the periods to test the threshold */ 152 ret = joySetThreshold(joyid, period[i]); 153 if (!win98 && (1 << i) & threshold_error) 154 ok(ret == MMSYSERR_INVALPARAM, "Test [%d]: Expected %d, got %d\n", i, MMSYSERR_INVALPARAM, ret); 155 else 156 ok(ret == JOYERR_NOERROR, "Test [%d]: Expected %d, got %d\n", i, JOYERR_NOERROR, ret); 157 par = 0xdead; 158 ret = joyGetThreshold(joyid, &par); 159 ok(ret == JOYERR_NOERROR, "Test [%d]: Expected %d, got %d\n", i, JOYERR_NOERROR, ret); 160 if (!win98 || i < 8) 161 { 162 if ((1 << i) & threshold_error) 163 ok(par == period[8], "Test [%d]: Expected %d, got %d\n", i, period[8], par); 164 else 165 ok(par == period[i], "Test [%d]: Expected %d, got %d\n", i, period[i], par); 166 } 167 } 168 169 /* Position tests */ 170 ret = joyGetPos(joyid, NULL); 171 ok(ret == MMSYSERR_INVALPARAM, "Expected %d, got %d\n", MMSYSERR_INVALPARAM, ret); 172 ret = joyGetPos(joyid, &info); 173 ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); 174 ret = joyGetPosEx(joyid, NULL); 175 ok(ret == MMSYSERR_INVALPARAM || broken(win8 && ret == JOYERR_PARMS) /* Win 8 */, 176 "Expected %d, got %d\n", MMSYSERR_INVALPARAM, ret); 177 memset(&infoex, 0, sizeof(infoex)); 178 ret = joyGetPosEx(joyid, &infoex.ex); 179 ok(ret == JOYERR_PARMS || broken(win98 && ret == MMSYSERR_INVALPARAM), 180 "Expected %d, got %d\n", JOYERR_PARMS, ret); 181 infoex.ex.dwSize = sizeof(infoex.ex); 182 ret = joyGetPosEx(joyid, &infoex.ex); 183 ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); 184 infoex.ex.dwSize = sizeof(infoex.ex) - 1; 185 ret = joyGetPosEx(joyid, &infoex.ex); 186 ok(ret == JOYERR_PARMS || broken(win98 && ret == MMSYSERR_INVALPARAM), 187 "Expected %d, got %d\n", JOYERR_PARMS, ret); 188 infoex.ex.dwSize = sizeof(infoex); 189 ret = joyGetPosEx(joyid, &infoex.ex); 190 ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); 191 192 infoex.ex.dwSize = sizeof(infoex.ex); 193 for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) 194 { 195 infoex.ex.dwFlags = flags[i]; 196 ret = joyGetPosEx(joyid, &infoex.ex); 197 ok(ret == JOYERR_NOERROR, "Expected %d, got %d\n", JOYERR_NOERROR, ret); 198 } 199 200 /* the interactive tests spans for 15 seconds, a 500ms polling is used to get 201 * changes in the joystick. */ 202 if (winetest_interactive) 203 { 204 #define MAX_TIME 15000 205 DWORD tick = GetTickCount(), spent; 206 infoex.ex.dwSize = sizeof(infoex.ex); 207 infoex.ex.dwFlags = JOY_RETURNALL; 208 do 209 { 210 spent = GetTickCount() - tick; 211 ret = joyGetPosEx(joyid, &infoex.ex); 212 if (ret == JOYERR_NOERROR) 213 { 214 trace("X: %5d, Y: %5d, Z: %5d, POV: %5d\n", 215 infoex.ex.dwXpos, infoex.ex.dwYpos, infoex.ex.dwZpos, infoex.ex.dwPOV); 216 trace("R: %5d, U: %5d, V: %5d\n", 217 infoex.ex.dwRpos, infoex.ex.dwUpos, infoex.ex.dwVpos); 218 trace("BUTTONS: 0x%04X, BUTTON_COUNT: %2d, REMAINING: %d ms\n\n", 219 infoex.ex.dwButtons, infoex.ex.dwButtonNumber, MAX_TIME - spent); 220 } 221 Sleep(500); 222 } 223 while (spent < MAX_TIME); 224 #undef MAX_TIME 225 } 226 else 227 skip("Skipping interactive tests for the joystick\n"); 228 } 229 230 START_TEST(joystick) 231 { 232 create_window(); 233 test_api(); 234 destroy_window(); 235 } 236