Sweden-Number/dlls/winmm/joystick.c

357 lines
11 KiB
C

/* -*- tab-width: 8; c-basic-offset: 4 -*- */
/*
* joystick functions
*
* Copyright 1997 Andreas Mohr
* 2000 Wolfgang Schwotzer
* Eric Pouech
*
* 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
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "windef.h"
#include "winbase.h"
#include "mmsystem.h"
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
#include "mmddk.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(winmm);
#define JOY_PERIOD_MIN (10) /* min Capture time period */
#define JOY_PERIOD_MAX (1000) /* max Capture time period */
typedef struct tagWINE_JOYSTICK {
JOYINFO ji;
HWND hCapture;
UINT wTimer;
DWORD threshold;
BOOL bChanged;
HDRVR hDriver;
} WINE_JOYSTICK;
static WINE_JOYSTICK joysticks[16];
static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff)
{
unsigned int diff = x > y ? x - y : y - x;
return diff <= max_diff;
}
/**************************************************************************
* JOY_LoadDriver [internal]
*/
static BOOL JOY_LoadDriver(DWORD dwJoyID)
{
static BOOL winejoystick_missing = FALSE;
if (dwJoyID >= ARRAY_SIZE(joysticks) || winejoystick_missing) return FALSE;
if (joysticks[dwJoyID].hDriver) return TRUE;
joysticks[dwJoyID].hDriver = OpenDriverA( "winejoystick.drv", 0, dwJoyID );
if (!joysticks[dwJoyID].hDriver)
{
WARN("OpenDriverA(\"winejoystick.drv\") failed\n");
/* The default driver is missing, don't attempt to load it again */
winejoystick_missing = TRUE;
}
return (joysticks[dwJoyID].hDriver != 0);
}
/**************************************************************************
* JOY_Timer [internal]
*/
static void CALLBACK JOY_Timer(HWND hWnd, UINT wMsg, UINT_PTR wTimer, DWORD dwTime)
{
int i;
WINE_JOYSTICK* joy;
MMRESULT res;
JOYINFO ji;
LONG pos;
unsigned buttonChange;
for (i = 0; i < ARRAY_SIZE(joysticks); i++)
{
joy = &joysticks[i];
if (joy->hCapture != hWnd) continue;
res = joyGetPos(i, &ji);
if (res != JOYERR_NOERROR) {
WARN("joyGetPos failed: %08x\n", res);
continue;
}
pos = MAKELONG(ji.wXpos, ji.wYpos);
if (!joy->bChanged ||
!compare_uint(joy->ji.wXpos, ji.wXpos, joy->threshold) ||
!compare_uint(joy->ji.wYpos, ji.wYpos, joy->threshold)) {
SendMessageA(joy->hCapture, MM_JOY1MOVE + i, ji.wButtons, pos);
joy->ji.wXpos = ji.wXpos;
joy->ji.wYpos = ji.wYpos;
}
if (!joy->bChanged ||
!compare_uint(joy->ji.wZpos, ji.wZpos, joy->threshold)) {
SendMessageA(joy->hCapture, MM_JOY1ZMOVE + i, ji.wButtons, pos);
joy->ji.wZpos = ji.wZpos;
}
if ((buttonChange = joy->ji.wButtons ^ ji.wButtons) != 0) {
if (ji.wButtons & buttonChange)
SendMessageA(joy->hCapture, MM_JOY1BUTTONDOWN + i,
(buttonChange << 8) | (ji.wButtons & buttonChange), pos);
if (joy->ji.wButtons & buttonChange)
SendMessageA(joy->hCapture, MM_JOY1BUTTONUP + i,
(buttonChange << 8) | (joy->ji.wButtons & buttonChange), pos);
joy->ji.wButtons = ji.wButtons;
}
}
}
/**************************************************************************
* joyConfigChanged [WINMM.@]
*/
MMRESULT WINAPI joyConfigChanged(DWORD flags)
{
FIXME("(%x) - stub\n", flags);
if (flags)
return JOYERR_PARMS;
return JOYERR_NOERROR;
}
/**************************************************************************
* joyGetNumDevs [WINMM.@]
*/
UINT WINAPI DECLSPEC_HOTPATCH joyGetNumDevs(void)
{
return ARRAY_SIZE(joysticks);
}
/**************************************************************************
* joyGetDevCapsW [WINMM.@]
*/
MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsW( UINT_PTR id, JOYCAPSW *caps, UINT size )
{
TRACE( "id %d, caps %p, size %u.\n", (int)id, caps, size );
if (!caps) return MMSYSERR_INVALPARAM;
if (size != sizeof(JOYCAPSW) && size != sizeof(JOYCAPS2W)) return JOYERR_PARMS;
memset( caps, 0, size );
wcscpy( caps->szRegKey, L"DINPUT.DLL" );
if (id == ~(UINT_PTR)0) return JOYERR_NOERROR;
if (id >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS;
if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
caps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */
caps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */
return SendDriverMessage( joysticks[id].hDriver, JDD_GETDEVCAPS, (LPARAM)caps, size );
}
/**************************************************************************
* joyGetDevCapsA [WINMM.@]
*/
MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsA( UINT_PTR id, JOYCAPSA *caps, UINT size )
{
UINT size_w = sizeof(JOYCAPS2W);
JOYCAPS2W caps_w;
MMRESULT res;
TRACE( "id %d, caps %p, size %u.\n", (int)id, caps, size );
if (!caps) return MMSYSERR_INVALPARAM;
if (size != sizeof(JOYCAPSA) && size != sizeof(JOYCAPS2A)) return JOYERR_PARMS;
if (size == sizeof(JOYCAPSA)) size_w = sizeof(JOYCAPSW);
res = joyGetDevCapsW( id, (JOYCAPSW *)&caps_w, size_w );
if (res) return res;
caps->wMid = caps_w.wMid;
caps->wPid = caps_w.wPid;
WideCharToMultiByte( CP_ACP, 0, caps_w.szPname, -1, caps->szPname,
sizeof(caps->szPname), NULL, NULL );
caps->wXmin = caps_w.wXmin;
caps->wXmax = caps_w.wXmax;
caps->wYmin = caps_w.wYmin;
caps->wYmax = caps_w.wYmax;
caps->wZmin = caps_w.wZmin;
caps->wZmax = caps_w.wZmax;
caps->wNumButtons = caps_w.wNumButtons;
caps->wPeriodMin = caps_w.wPeriodMin;
caps->wPeriodMax = caps_w.wPeriodMax;
caps->wRmin = caps_w.wRmin;
caps->wRmax = caps_w.wRmax;
caps->wUmin = caps_w.wUmin;
caps->wUmax = caps_w.wUmax;
caps->wVmin = caps_w.wVmin;
caps->wVmax = caps_w.wVmax;
caps->wCaps = caps_w.wCaps;
caps->wMaxAxes = caps_w.wMaxAxes;
caps->wNumAxes = caps_w.wNumAxes;
caps->wMaxButtons = caps_w.wMaxButtons;
WideCharToMultiByte( CP_ACP, 0, caps_w.szRegKey, -1, caps->szRegKey,
sizeof(caps->szRegKey), NULL, NULL );
WideCharToMultiByte( CP_ACP, 0, caps_w.szOEMVxD, -1, caps->szOEMVxD,
sizeof(caps->szOEMVxD), NULL, NULL );
if (size == sizeof(JOYCAPS2A))
{
JOYCAPS2A *caps2_a = (JOYCAPS2A *)caps;
caps2_a->ManufacturerGuid = caps_w.ManufacturerGuid;
caps2_a->ProductGuid = caps_w.ProductGuid;
caps2_a->NameGuid = caps_w.NameGuid;
}
return JOYERR_NOERROR;
}
/**************************************************************************
* joyGetPosEx [WINMM.@]
*/
MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo)
{
TRACE("(%d, %p);\n", wID, lpInfo);
if (!lpInfo) return MMSYSERR_INVALPARAM;
if (wID >= ARRAY_SIZE(joysticks) || lpInfo->dwSize < sizeof(JOYINFOEX)) return JOYERR_PARMS;
if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
lpInfo->dwXpos = 0;
lpInfo->dwYpos = 0;
lpInfo->dwZpos = 0;
lpInfo->dwRpos = 0;
lpInfo->dwUpos = 0;
lpInfo->dwVpos = 0;
lpInfo->dwButtons = 0;
lpInfo->dwButtonNumber = 0;
lpInfo->dwPOV = 0;
lpInfo->dwReserved1 = 0;
lpInfo->dwReserved2 = 0;
return SendDriverMessage( joysticks[wID].hDriver, JDD_GETPOSEX, (LPARAM)lpInfo, 0 );
}
/**************************************************************************
* joyGetPos [WINMM.@]
*/
MMRESULT WINAPI joyGetPos( UINT id, JOYINFO *info )
{
JOYINFOEX infoex =
{
.dwSize = sizeof(JOYINFOEX),
.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS,
};
MMRESULT res;
TRACE( "id %u, info %p.\n", id, info );
if (!info) return MMSYSERR_INVALPARAM;
if ((res = joyGetPosEx( id, &infoex ))) return res;
info->wXpos = infoex.dwXpos;
info->wYpos = infoex.dwYpos;
info->wZpos = infoex.dwZpos;
info->wButtons = infoex.dwButtons;
return JOYERR_NOERROR;
}
/**************************************************************************
* joyGetThreshold [WINMM.@]
*/
MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold)
{
TRACE("(%04X, %p);\n", wID, lpThreshold);
if (wID >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS;
*lpThreshold = joysticks[wID].threshold;
return JOYERR_NOERROR;
}
/**************************************************************************
* joyReleaseCapture [WINMM.@]
*/
MMRESULT WINAPI joyReleaseCapture(UINT wID)
{
TRACE("(%04X);\n", wID);
if (wID >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS;
if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
if (joysticks[wID].hCapture)
{
KillTimer( joysticks[wID].hCapture, joysticks[wID].wTimer );
joysticks[wID].hCapture = 0;
joysticks[wID].wTimer = 0;
}
else
TRACE("Joystick is not captured, ignoring request.\n");
return JOYERR_NOERROR;
}
/**************************************************************************
* joySetCapture [WINMM.@]
*/
MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged)
{
TRACE("(%p, %04X, %d, %d);\n", hWnd, wID, wPeriod, bChanged);
if (wID >= ARRAY_SIZE(joysticks) || hWnd == 0) return JOYERR_PARMS;
if (wPeriod<JOY_PERIOD_MIN) wPeriod = JOY_PERIOD_MIN;
else if(wPeriod>JOY_PERIOD_MAX) wPeriod = JOY_PERIOD_MAX;
if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
if (joysticks[wID].hCapture || !IsWindow( hWnd )) return JOYERR_NOCANDO; /* FIXME: what should be returned ? */
if (joyGetPos( wID, &joysticks[wID].ji ) != JOYERR_NOERROR) return JOYERR_UNPLUGGED;
if ((joysticks[wID].wTimer = SetTimer( hWnd, 0, wPeriod, JOY_Timer )) == 0) return JOYERR_NOCANDO;
joysticks[wID].hCapture = hWnd;
joysticks[wID].bChanged = bChanged;
return JOYERR_NOERROR;
}
/**************************************************************************
* joySetThreshold [WINMM.@]
*/
MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold)
{
TRACE("(%04X, %d);\n", wID, wThreshold);
if (wID >= ARRAY_SIZE(joysticks) || wThreshold > 65535) return MMSYSERR_INVALPARAM;
joysticks[wID].threshold = wThreshold;
return JOYERR_NOERROR;
}