1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */ 2 /* 3 * joystick functions 4 * 5 * Copyright 1997 Andreas Mohr 6 * 2000 Wolfgang Schwotzer 7 * Eric Pouech 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2.1 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 22 */ 23 24 #include "winemm.h" 25 26 #ifdef HAVE_UNISTD_H 27 # include <unistd.h> 28 #endif 29 30 #include <stdlib.h> 31 32 #ifdef HAVE_SYS_IOCTL_H 33 #include <sys/ioctl.h> 34 #endif 35 36 WINE_DEFAULT_DEBUG_CHANNEL(winmm); 37 38 #define MAXJOYSTICK (JOYSTICKID2 + 30) 39 #define JOY_PERIOD_MIN (10) /* min Capture time period */ 40 #define JOY_PERIOD_MAX (1000) /* max Capture time period */ 41 42 typedef struct tagWINE_JOYSTICK { 43 JOYINFO ji; 44 HWND hCapture; 45 UINT wTimer; 46 DWORD threshold; 47 BOOL bChanged; 48 HDRVR hDriver; 49 } WINE_JOYSTICK; 50 51 static WINE_JOYSTICK JOY_Sticks[MAXJOYSTICK]; 52 53 /************************************************************************** 54 * JOY_LoadDriver [internal] 55 */ 56 static BOOL JOY_LoadDriver(DWORD dwJoyID) 57 { 58 static BOOL winejoystick_missing = FALSE; 59 60 if (dwJoyID >= MAXJOYSTICK || winejoystick_missing) 61 return FALSE; 62 if (JOY_Sticks[dwJoyID].hDriver) 63 return TRUE; 64 65 JOY_Sticks[dwJoyID].hDriver = OpenDriverA("winejoystick.drv", 0, dwJoyID); 66 67 if (!JOY_Sticks[dwJoyID].hDriver) 68 { 69 WARN("OpenDriverA(\"winejoystick.drv\") failed\n"); 70 71 /* The default driver is missing, don't attempt to load it again */ 72 winejoystick_missing = TRUE; 73 } 74 75 return (JOY_Sticks[dwJoyID].hDriver != 0); 76 } 77 78 /************************************************************************** 79 * JOY_Timer [internal] 80 */ 81 static void CALLBACK JOY_Timer(HWND hWnd, UINT wMsg, UINT_PTR wTimer, DWORD dwTime) 82 { 83 int i; 84 WINE_JOYSTICK* joy; 85 JOYINFO ji; 86 LONG pos; 87 unsigned buttonChange; 88 89 for (i = 0; i < MAXJOYSTICK; i++) { 90 joy = &JOY_Sticks[i]; 91 92 if (joy->hCapture != hWnd) continue; 93 94 joyGetPos(i, &ji); 95 pos = MAKELONG(ji.wXpos, ji.wYpos); 96 97 if (!joy->bChanged || 98 abs(joy->ji.wXpos - ji.wXpos) > joy->threshold || 99 abs(joy->ji.wYpos - ji.wYpos) > joy->threshold) { 100 SendMessageA(joy->hCapture, MM_JOY1MOVE + i, ji.wButtons, pos); 101 joy->ji.wXpos = ji.wXpos; 102 joy->ji.wYpos = ji.wYpos; 103 } 104 if (!joy->bChanged || 105 abs(joy->ji.wZpos - ji.wZpos) > joy->threshold) { 106 SendMessageA(joy->hCapture, MM_JOY1ZMOVE + i, ji.wButtons, pos); 107 joy->ji.wZpos = ji.wZpos; 108 } 109 if ((buttonChange = joy->ji.wButtons ^ ji.wButtons) != 0) { 110 if (ji.wButtons & buttonChange) 111 SendMessageA(joy->hCapture, MM_JOY1BUTTONDOWN + i, 112 (buttonChange << 8) | (ji.wButtons & buttonChange), pos); 113 if (joy->ji.wButtons & buttonChange) 114 SendMessageA(joy->hCapture, MM_JOY1BUTTONUP + i, 115 (buttonChange << 8) | (joy->ji.wButtons & buttonChange), pos); 116 joy->ji.wButtons = ji.wButtons; 117 } 118 } 119 } 120 121 /************************************************************************** 122 * joyConfigChanged [WINMM.@] 123 */ 124 MMRESULT WINAPI joyConfigChanged(DWORD flags) 125 { 126 FIXME("(%x) - stub\n", flags); 127 128 if (flags) 129 return JOYERR_PARMS; 130 131 return JOYERR_NOERROR; 132 } 133 134 /************************************************************************** 135 * joyGetNumDevs [WINMM.@] 136 */ 137 UINT WINAPI DECLSPEC_HOTPATCH joyGetNumDevs(void) 138 { 139 UINT ret = 0; 140 int i; 141 142 for (i = 0; i < MAXJOYSTICK; i++) { 143 if (JOY_LoadDriver(i)) { 144 ret += SendDriverMessage(JOY_Sticks[i].hDriver, JDD_GETNUMDEVS, 0, 0); 145 } 146 } 147 return ret; 148 } 149 150 /************************************************************************** 151 * joyGetDevCapsW [WINMM.@] 152 */ 153 MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsW(UINT_PTR wID, LPJOYCAPSW lpCaps, UINT wSize) 154 { 155 if (wID >= MAXJOYSTICK) return JOYERR_PARMS; 156 if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; 157 158 lpCaps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */ 159 lpCaps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */ 160 161 return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETDEVCAPS, (LPARAM)lpCaps, wSize); 162 } 163 164 /************************************************************************** 165 * joyGetDevCapsA [WINMM.@] 166 */ 167 MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsA(UINT_PTR wID, LPJOYCAPSA lpCaps, UINT wSize) 168 { 169 JOYCAPSW jcw; 170 MMRESULT ret; 171 172 if (lpCaps == NULL) return MMSYSERR_INVALPARAM; 173 174 ret = joyGetDevCapsW(wID, &jcw, sizeof(jcw)); 175 176 if (ret == JOYERR_NOERROR) 177 { 178 lpCaps->wMid = jcw.wMid; 179 lpCaps->wPid = jcw.wPid; 180 WideCharToMultiByte( CP_ACP, 0, jcw.szPname, -1, lpCaps->szPname, 181 sizeof(lpCaps->szPname), NULL, NULL ); 182 lpCaps->wXmin = jcw.wXmin; 183 lpCaps->wXmax = jcw.wXmax; 184 lpCaps->wYmin = jcw.wYmin; 185 lpCaps->wYmax = jcw.wYmax; 186 lpCaps->wZmin = jcw.wZmin; 187 lpCaps->wZmax = jcw.wZmax; 188 lpCaps->wNumButtons = jcw.wNumButtons; 189 lpCaps->wPeriodMin = jcw.wPeriodMin; 190 lpCaps->wPeriodMax = jcw.wPeriodMax; 191 192 if (wSize >= sizeof(JOYCAPSA)) { /* Win95 extensions ? */ 193 lpCaps->wRmin = jcw.wRmin; 194 lpCaps->wRmax = jcw.wRmax; 195 lpCaps->wUmin = jcw.wUmin; 196 lpCaps->wUmax = jcw.wUmax; 197 lpCaps->wVmin = jcw.wVmin; 198 lpCaps->wVmax = jcw.wVmax; 199 lpCaps->wCaps = jcw.wCaps; 200 lpCaps->wMaxAxes = jcw.wMaxAxes; 201 lpCaps->wNumAxes = jcw.wNumAxes; 202 lpCaps->wMaxButtons = jcw.wMaxButtons; 203 WideCharToMultiByte( CP_ACP, 0, jcw.szRegKey, -1, lpCaps->szRegKey, 204 sizeof(lpCaps->szRegKey), NULL, NULL ); 205 WideCharToMultiByte( CP_ACP, 0, jcw.szOEMVxD, -1, lpCaps->szOEMVxD, 206 sizeof(lpCaps->szOEMVxD), NULL, NULL ); 207 } 208 } 209 210 return ret; 211 } 212 213 /************************************************************************** 214 * joyGetPosEx [WINMM.@] 215 */ 216 MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo) 217 { 218 TRACE("(%d, %p);\n", wID, lpInfo); 219 220 if (wID >= MAXJOYSTICK) return JOYERR_PARMS; 221 if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; 222 223 lpInfo->dwXpos = 0; 224 lpInfo->dwYpos = 0; 225 lpInfo->dwZpos = 0; 226 lpInfo->dwRpos = 0; 227 lpInfo->dwUpos = 0; 228 lpInfo->dwVpos = 0; 229 lpInfo->dwButtons = 0; 230 lpInfo->dwButtonNumber = 0; 231 lpInfo->dwPOV = 0; 232 lpInfo->dwReserved1 = 0; 233 lpInfo->dwReserved2 = 0; 234 235 return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOSEX, (LPARAM)lpInfo, 0); 236 } 237 238 /************************************************************************** 239 * joyGetPos [WINMM.@] 240 */ 241 MMRESULT WINAPI joyGetPos(UINT wID, LPJOYINFO lpInfo) 242 { 243 TRACE("(%d, %p);\n", wID, lpInfo); 244 245 if (wID >= MAXJOYSTICK) return JOYERR_PARMS; 246 if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; 247 248 lpInfo->wXpos = 0; 249 lpInfo->wYpos = 0; 250 lpInfo->wZpos = 0; 251 lpInfo->wButtons = 0; 252 253 return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOS, (LPARAM)lpInfo, 0); 254 } 255 256 /************************************************************************** 257 * joyGetThreshold [WINMM.@] 258 */ 259 MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold) 260 { 261 TRACE("(%04X, %p);\n", wID, lpThreshold); 262 263 if (wID >= MAXJOYSTICK) return JOYERR_PARMS; 264 265 *lpThreshold = JOY_Sticks[wID].threshold; 266 return JOYERR_NOERROR; 267 } 268 269 /************************************************************************** 270 * joyReleaseCapture [WINMM.@] 271 */ 272 MMRESULT WINAPI joyReleaseCapture(UINT wID) 273 { 274 TRACE("(%04X);\n", wID); 275 276 if (wID >= MAXJOYSTICK) return JOYERR_PARMS; 277 if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; 278 if (!JOY_Sticks[wID].hCapture) return JOYERR_NOCANDO; 279 280 KillTimer(JOY_Sticks[wID].hCapture, JOY_Sticks[wID].wTimer); 281 JOY_Sticks[wID].hCapture = 0; 282 JOY_Sticks[wID].wTimer = 0; 283 284 return JOYERR_NOERROR; 285 } 286 287 /************************************************************************** 288 * joySetCapture [WINMM.@] 289 */ 290 MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged) 291 { 292 TRACE("(%p, %04X, %d, %d);\n", hWnd, wID, wPeriod, bChanged); 293 294 if (wID >= MAXJOYSTICK || hWnd == 0) return JOYERR_PARMS; 295 if (wPeriod<JOY_PERIOD_MIN || wPeriod>JOY_PERIOD_MAX) return JOYERR_PARMS; 296 if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; 297 298 if (JOY_Sticks[wID].hCapture || !IsWindow(hWnd)) 299 return JOYERR_NOCANDO; /* FIXME: what should be returned ? */ 300 301 if (joyGetPos(wID, &JOY_Sticks[wID].ji) != JOYERR_NOERROR) 302 return JOYERR_UNPLUGGED; 303 304 if ((JOY_Sticks[wID].wTimer = SetTimer(hWnd, 0, wPeriod, JOY_Timer)) == 0) 305 return JOYERR_NOCANDO; 306 307 JOY_Sticks[wID].hCapture = hWnd; 308 JOY_Sticks[wID].bChanged = bChanged; 309 310 return JOYERR_NOERROR; 311 } 312 313 /************************************************************************** 314 * joySetThreshold [WINMM.@] 315 */ 316 MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold) 317 { 318 TRACE("(%04X, %d);\n", wID, wThreshold); 319 320 if (wID >= MAXJOYSTICK) return MMSYSERR_INVALPARAM; 321 322 JOY_Sticks[wID].threshold = wThreshold; 323 324 return JOYERR_NOERROR; 325 } 326