--- vendor/wine/dlls/winmm/current/driver.c 2004-12-31 16:30:04 UTC (rev 12637)
+++ vendor/wine/dlls/winmm/current/driver.c 2004-12-31 16:34:31 UTC (rev 12638)
@@ -0,0 +1,567 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+
+/*
+ * WINE Drivers functions
+ *
+ * Copyright 1994 Martin Ayotte
+ * Copyright 1998 Marcus Meissner
+ * Copyright 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "mmddk.h"
+#include "winemm.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(driver);
+
+#define HKLM_BASE "Software\\Microsoft\\Windows NT\\CurrentVersion"
+
+static LPWINE_DRIVER lpDrvItemList /* = NULL */;
+
+WINE_MMTHREAD* (*pFnGetMMThread16)(UINT16 h) /* = NULL */;
+LPWINE_DRIVER (*pFnOpenDriver16)(LPCSTR,LPCSTR,LPARAM) /* = NULL */;
+LRESULT (*pFnCloseDriver16)(UINT16,LPARAM,LPARAM) /* = NULL */;
+LRESULT (*pFnSendMessage16)(UINT16,UINT,LPARAM,LPARAM) /* = NULL */;
+
+/**************************************************************************
+ * DRIVER_GetNumberOfModuleRefs [internal]
+ *
+ * Returns the number of open drivers which share the same module.
+ */
+static unsigned DRIVER_GetNumberOfModuleRefs(HMODULE hModule, WINE_DRIVER** found)
+{
+ LPWINE_DRIVER lpDrv;
+ unsigned count = 0;
+
+ if (found) *found = NULL;
+ for (lpDrv = lpDrvItemList; lpDrv; lpDrv = lpDrv->lpNextItem)
+ {
+ if (!(lpDrv->dwFlags & WINE_GDF_16BIT) && lpDrv->d.d32.hModule == hModule)
+ {
+ if (found && !*found) *found = lpDrv;
+ count++;
+ }
+ }
+ return count;
+}
+
+/**************************************************************************
+ * DRIVER_FindFromHDrvr [internal]
+ *
+ * From a hDrvr being 32 bits, returns the WINE internal structure.
+ */
+LPWINE_DRIVER DRIVER_FindFromHDrvr(HDRVR hDrvr)
+{
+ LPWINE_DRIVER d = (LPWINE_DRIVER)hDrvr;
+
+ if (hDrvr && HeapValidate(GetProcessHeap(), 0, d) && d->dwMagic == WINE_DI_MAGIC) {
+ return d;
+ }
+ return NULL;
+}
+
+/**************************************************************************
+ * DRIVER_SendMessage [internal]
+ */
+static LRESULT inline DRIVER_SendMessage(LPWINE_DRIVER lpDrv, UINT msg,
+ LPARAM lParam1, LPARAM lParam2)
+{
+ LRESULT ret = 0;
+
+ if (lpDrv->dwFlags & WINE_GDF_16BIT) {
+ /* no need to check mmsystem presence: the driver must have been opened as a 16 bit one,
+ */
+ if (pFnSendMessage16)
+ ret = pFnSendMessage16(lpDrv->d.d16.hDriver16, msg, lParam1, lParam2);
+ } else {
+ TRACE("Before call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx\n",
+ lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2);
+ ret = lpDrv->d.d32.lpDrvProc(lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2);
+ TRACE("After call32 proc=%p drvrID=%08lx hDrv=%p wMsg=%04x p1=%08lx p2=%08lx => %08lx\n",
+ lpDrv->d.d32.lpDrvProc, lpDrv->d.d32.dwDriverID, (HDRVR)lpDrv, msg, lParam1, lParam2, ret);
+ }
+ return ret;
+}
+
+/**************************************************************************
+ * SendDriverMessage [WINMM.@]
+ * DrvSendMessage [WINMM.@]
+ */
+LRESULT WINAPI SendDriverMessage(HDRVR hDriver, UINT msg, LPARAM lParam1,
+ LPARAM lParam2)
+{
+ LPWINE_DRIVER lpDrv;
+ LRESULT retval = 0;
+
+ TRACE("(%p, %04X, %08lX, %08lX)\n", hDriver, msg, lParam1, lParam2);
+
+ if ((lpDrv = DRIVER_FindFromHDrvr(hDriver)) != NULL) {
+ retval = DRIVER_SendMessage(lpDrv, msg, lParam1, lParam2);
+ } else {
+ WARN("Bad driver handle %p\n", hDriver);
+ }
+ TRACE("retval = %ld\n", retval);
+
+ return retval;
+}
+
+/**************************************************************************
+ * DRIVER_RemoveFromList [internal]
+ *
+ * Generates all the logic to handle driver closure / deletion
+ * Removes a driver struct to the list of open drivers.
+ */
+static BOOL DRIVER_RemoveFromList(LPWINE_DRIVER lpDrv)
+{
+ if (!(lpDrv->dwFlags & WINE_GDF_16BIT)) {
+ /* last of this driver in list ? */
+ if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 1) {
+ DRIVER_SendMessage(lpDrv, DRV_DISABLE, 0L, 0L);
+ DRIVER_SendMessage(lpDrv, DRV_FREE, 0L, 0L);
+ }
+ }
+
+ if (lpDrv->lpPrevItem)
+ lpDrv->lpPrevItem->lpNextItem = lpDrv->lpNextItem;
+ else
+ lpDrvItemList = lpDrv->lpNextItem;
+ if (lpDrv->lpNextItem)
+ lpDrv->lpNextItem->lpPrevItem = lpDrv->lpPrevItem;
+ /* trash magic number */
+ lpDrv->dwMagic ^= 0xa5a5a5a5;
+
+ return TRUE;
+}
+
+/**************************************************************************
+ * DRIVER_AddToList [internal]
+ *
+ * Adds a driver struct to the list of open drivers.
+ * Generates all the logic to handle driver creation / open.
+ */
+static BOOL DRIVER_AddToList(LPWINE_DRIVER lpNewDrv, LPARAM lParam1, LPARAM lParam2)
+{
+ lpNewDrv->dwMagic = WINE_DI_MAGIC;
+ /* First driver to be loaded for this module, need to load correctly the module */
+ if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) {
+ /* first of this driver in list ? */
+ if (DRIVER_GetNumberOfModuleRefs(lpNewDrv->d.d32.hModule, NULL) == 0) {
+ if (DRIVER_SendMessage(lpNewDrv, DRV_LOAD, 0L, 0L) != DRV_SUCCESS) {
+ TRACE("DRV_LOAD failed on driver 0x%08lx\n", (DWORD)lpNewDrv);
+ return FALSE;
+ }
+ /* returned value is not checked */
+ DRIVER_SendMessage(lpNewDrv, DRV_ENABLE, 0L, 0L);
+ }
+ }
+
+ lpNewDrv->lpNextItem = NULL;
+ if (lpDrvItemList == NULL) {
+ lpDrvItemList = lpNewDrv;
+ lpNewDrv->lpPrevItem = NULL;
+ } else {
+ LPWINE_DRIVER lpDrv = lpDrvItemList; /* find end of list */
+ while (lpDrv->lpNextItem != NULL)
+ lpDrv = lpDrv->lpNextItem;
+
+ lpDrv->lpNextItem = lpNewDrv;
+ lpNewDrv->lpPrevItem = lpDrv;
+ }
+
+ if (!(lpNewDrv->dwFlags & WINE_GDF_16BIT)) {
+ /* Now just open a new instance of a driver on this module */
+ lpNewDrv->d.d32.dwDriverID = DRIVER_SendMessage(lpNewDrv, DRV_OPEN, lParam1, lParam2);
+
+ if (lpNewDrv->d.d32.dwDriverID == 0) {
+ TRACE("DRV_OPEN failed on driver 0x%08lx\n", (DWORD)lpNewDrv);
+ DRIVER_RemoveFromList(lpNewDrv);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**************************************************************************
+ * DRIVER_GetLibName [internal]
+ *
+ */
+BOOL DRIVER_GetLibName(LPCSTR keyName, LPCSTR sectName, LPSTR buf, int sz)
+{
+ HKEY hKey, hSecKey;
+ DWORD bufLen, lRet;
+
+ lRet = RegOpenKeyExA(HKEY_LOCAL_MACHINE, HKLM_BASE, 0, KEY_QUERY_VALUE, &hKey);
+ if (lRet == ERROR_SUCCESS) {
+ lRet = RegOpenKeyExA(hKey, sectName, 0, KEY_QUERY_VALUE, &hSecKey);
+ if (lRet == ERROR_SUCCESS) {
+ lRet = RegQueryValueExA(hSecKey, keyName, 0, 0, buf, &bufLen);
+ RegCloseKey( hSecKey );
+ }
+ RegCloseKey( hKey );
+ }
+ if (lRet == ERROR_SUCCESS) return TRUE;
+ /* default to system.ini if we can't find it in the registry,
+ * to support native installations where system.ini is still used */
+ return GetPrivateProfileStringA(sectName, keyName, "", buf, sz, "SYSTEM.INI");
+}
+
+/**************************************************************************
+ * DRIVER_TryOpenDriver32 [internal]
+ *
+ * Tries to load a 32 bit driver whose DLL's (module) name is fn
+ */
+LPWINE_DRIVER DRIVER_TryOpenDriver32(LPCSTR fn, LPARAM lParam2)
+{
+ LPWINE_DRIVER lpDrv = NULL;
+ HMODULE hModule = 0;
+ LPSTR ptr;
+ LPCSTR cause = 0;
+
+ TRACE("(%s, %08lX);\n", debugstr_a(fn), lParam2);
+
+ if ((ptr = strchr(fn, ' ')) != NULL) {
+ *ptr++ = '\0';
+ while (*ptr == ' ') ptr++;
+ if (*ptr == '\0') ptr = NULL;
+ }
+
+ lpDrv = HeapAlloc(GetProcessHeap(), 0, sizeof(WINE_DRIVER));
+ if (lpDrv == NULL) {cause = "OOM"; goto exit;}
+
+ if ((hModule = LoadLibraryA(fn)) == 0) {cause = "Not a 32 bit lib"; goto exit;}
+
+ lpDrv->d.d32.lpDrvProc = (DRIVERPROC)GetProcAddress(hModule, "DriverProc");
+ if (lpDrv->d.d32.lpDrvProc == NULL) {cause = "no DriverProc"; goto exit;}
+
+ lpDrv->dwFlags = 0;
+ lpDrv->d.d32.hModule = hModule;
+ lpDrv->d.d32.dwDriverID = 0;
+
+ /* Win32 installable drivers must support a two phase opening scheme:
+ * + first open with NULL as lParam2 (session instance),
+ * + then do a second open with the real non null lParam2)
+ */
+ if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, NULL) == 0 && lParam2)
+ {
+ LPWINE_DRIVER ret;
+
+ if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, 0L))
+ {
+ cause = "load0 failed";
+ goto exit;
+ }
+ ret = DRIVER_TryOpenDriver32(fn, lParam2);
+ if (!ret)
+ {
+ CloseDriver((HDRVR)lpDrv, 0L, 0L);
+ cause = "load1 failed";
+ goto exit;
+ }
+ return ret;
+ }
+
+ if (!DRIVER_AddToList(lpDrv, (LPARAM)ptr, lParam2))
+ {cause = "load failed"; goto exit;}
+
+ TRACE("=> %p\n", lpDrv);
+ return lpDrv;
+ exit:
+ FreeLibrary(hModule);
+ HeapFree(GetProcessHeap(), 0, lpDrv);
+ TRACE("Unable to load 32 bit module %s: %s\n", debugstr_a(fn), cause);
+ return NULL;
+}
+
+/**************************************************************************
+ * OpenDriverA [WINMM.@]
+ * DrvOpenA [WINMM.@]
+ * (0,1,DRV_LOAD ,0 ,0)
+ * (0,1,DRV_ENABLE,0 ,0)
+ * (0,1,DRV_OPEN ,buf[256],0)
+ */
+HDRVR WINAPI OpenDriverA(LPCSTR lpDriverName, LPCSTR lpSectionName, LPARAM lParam2)
+{
+ LPWINE_DRIVER lpDrv = NULL;
+ char libName[128];
+ LPCSTR lsn = lpSectionName;
+
+ TRACE("(%s, %s, 0x%08lx);\n", debugstr_a(lpDriverName), debugstr_a(lpSectionName), lParam2);
+
+ if (lsn == NULL) {
+ lstrcpynA(libName, lpDriverName, sizeof(libName));
+
+ if ((lpDrv = DRIVER_TryOpenDriver32(libName, lParam2)))
+ goto the_end;
+ lsn = "Drivers32";
+ }
+ if (DRIVER_GetLibName(lpDriverName, lsn, libName, sizeof(libName)) &&
+ (lpDrv = DRIVER_TryOpenDriver32(libName, lParam2)))
+ goto the_end;
+
+ /* now we will try a 16 bit driver (and add all the glue to make it work... which
+ * is located in our mmsystem implementation)
+ * so ensure, we can load our mmsystem, otherwise just fail
+ */
+ WINMM_CheckForMMSystem();
+ if (pFnOpenDriver16 &&
+ (lpDrv = pFnOpenDriver16(lpDriverName, lpSectionName, lParam2)))
+ {
+ if (DRIVER_AddToList(lpDrv, 0, lParam2)) goto the_end;
+ HeapFree(GetProcessHeap(), 0, lpDrv);
+ }
+ TRACE("Failed to open driver %s from system.ini file, section %s\n", debugstr_a(lpDriverName), debugstr_a(lpSectionName));
+ return 0;
+
+ the_end:
+ if (lpDrv) TRACE("=> %08lx\n", (DWORD)lpDrv);
+ return (HDRVR)lpDrv;
+}
+
+/**************************************************************************
+ * OpenDriver [WINMM.@]
+ * DrvOpen [WINMM.@]
+ */
+HDRVR WINAPI OpenDriverW(LPCWSTR lpDriverName, LPCWSTR lpSectionName, LPARAM lParam)
+{
+ INT len;
+ LPSTR dn = NULL;
+ LPSTR sn = NULL;
+ HDRVR ret;
+
+ if (lpDriverName)
+ {
+ len = WideCharToMultiByte( CP_ACP, 0, lpDriverName, -1, NULL, 0, NULL, NULL );
+ dn = HeapAlloc( GetProcessHeap(), 0, len );
+ if (!dn) return 0;
+ WideCharToMultiByte( CP_ACP, 0, lpDriverName, -1, dn, len, NULL, NULL );
+ }
+
+ if (lpSectionName)
+ {
+ len = WideCharToMultiByte( CP_ACP, 0, lpSectionName, -1, NULL, 0, NULL, NULL );
+ sn = HeapAlloc( GetProcessHeap(), 0, len );
+ if (!sn) return 0;
+ WideCharToMultiByte( CP_ACP, 0, lpSectionName, -1, sn, len, NULL, NULL );
+ }
+
+ ret = OpenDriverA(dn, sn, lParam);
+
+ if (dn) HeapFree(GetProcessHeap(), 0, dn);
+ if (sn) HeapFree(GetProcessHeap(), 0, sn);
+ return ret;
+}
+
+/**************************************************************************
+ * CloseDriver [WINMM.@]
+ * DrvClose [WINMM.@]
+ */
+LRESULT WINAPI CloseDriver(HDRVR hDrvr, LPARAM lParam1, LPARAM lParam2)
+{
+ LPWINE_DRIVER lpDrv;
+
+ TRACE("(%p, %08lX, %08lX);\n", hDrvr, lParam1, lParam2);
+
+ if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL)
+ {
+ if (lpDrv->dwFlags & WINE_GDF_16BIT)
+ {
+ if (pFnCloseDriver16)
+ pFnCloseDriver16(lpDrv->d.d16.hDriver16, lParam1, lParam2);
+ }
+ else
+ {
+ DRIVER_SendMessage(lpDrv, DRV_CLOSE, lParam1, lParam2);
+ lpDrv->d.d32.dwDriverID = 0;
+ }
+ if (DRIVER_RemoveFromList(lpDrv)) {
+ if (!(lpDrv->dwFlags & WINE_GDF_16BIT))
+ {
+ LPWINE_DRIVER lpDrv0;
+
+ /* if driver has an opened session instance, we have to close it too */
+ if (DRIVER_GetNumberOfModuleRefs(lpDrv->d.d32.hModule, &lpDrv0) == 1)
+ {
+ DRIVER_SendMessage(lpDrv0, DRV_CLOSE, 0L, 0L);
+ lpDrv0->d.d32.dwDriverID = 0;
+ DRIVER_RemoveFromList(lpDrv0);
+ FreeLibrary(lpDrv0->d.d32.hModule);
+ HeapFree(GetProcessHeap(), 0, lpDrv0);
+ }
+ FreeLibrary(lpDrv->d.d32.hModule);
+ }
+ HeapFree(GetProcessHeap(), 0, lpDrv);
+ return TRUE;
+ }
+ }
+ WARN("Failed to close driver\n");
+ return FALSE;
+}
+
+/**************************************************************************
+ * GetDriverFlags [WINMM.@]
+ * [in] hDrvr handle to the driver
+ *
+ * Returns:
+ * 0x00000000 if hDrvr is an invalid handle
+ * 0x80000000 if hDrvr is a valid 32 bit driver
+ * 0x90000000 if hDrvr is a valid 16 bit driver
+ *
+ * native WINMM doesn't return those flags
+ * 0x80000000 for a valid 32 bit driver and that's it
+ * (I may have mixed up the two flags :-(
+ */
+DWORD WINAPI GetDriverFlags(HDRVR hDrvr)
+{
+ LPWINE_DRIVER lpDrv;
+ DWORD ret = 0;
+
+ TRACE("(%p)\n", hDrvr);
+
+ if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
+ ret = WINE_GDF_EXIST | lpDrv->dwFlags;
+ }
+ return ret;
+}
+
+/**************************************************************************
+ * GetDriverModuleHandle [WINMM.@]
+ * DrvGetModuleHandle [WINMM.@]
+ */
+HMODULE WINAPI GetDriverModuleHandle(HDRVR hDrvr)
+{
+ LPWINE_DRIVER lpDrv;
+ HMODULE hModule = 0;
+
+ TRACE("(%p);\n", hDrvr);
+
+ if ((lpDrv = DRIVER_FindFromHDrvr(hDrvr)) != NULL) {
+ if (!(lpDrv->dwFlags & WINE_GDF_16BIT))
+ hModule = lpDrv->d.d32.hModule;
+ }
+ TRACE("=> %p\n", hModule);
+ return hModule;
+}
+
+/**************************************************************************
+ * DefDriverProc [WINMM.@]
+ * DrvDefDriverProc [WINMM.@]
+ */
+LRESULT WINAPI DefDriverProc(DWORD_PTR dwDriverIdentifier, HDRVR hDrv,
+ UINT Msg, LPARAM lParam1, LPARAM lParam2)
+{
+ switch (Msg) {
+ case DRV_LOAD:
+ case DRV_FREE:
+ case DRV_ENABLE:
+ case DRV_DISABLE:
+ return 1;
+ case DRV_INSTALL:
+ case DRV_REMOVE:
+ return DRV_SUCCESS;
+ default:
+ return 0;
+ }
+}
+
+/**************************************************************************
+ * DriverCallback [WINMM.@]
+ */
+BOOL WINAPI DriverCallback(DWORD dwCallBack, UINT uFlags, HDRVR hDev,
+ UINT wMsg, DWORD dwUser, DWORD dwParam1,
+ DWORD dwParam2)
+{
+ TRACE("(%08lX, %04X, %p, %04X, %08lX, %08lX, %08lX); !\n",
+ dwCallBack, uFlags, hDev, wMsg, dwUser, dwParam1, dwParam2);
+
+ switch (uFlags & DCB_TYPEMASK) {
+ case DCB_NULL:
+ TRACE("Null !\n");
+ if (dwCallBack)
+ WARN("uFlags=%04X has null DCB value, but dwCallBack=%08lX is not null !\n", uFlags, dwCallBack);
+ break;
+ case DCB_WINDOW:
+ TRACE("Window(%04lX) handle=%p!\n", dwCallBack, hDev);
+ PostMessageA((HWND)dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
+ break;
+ case DCB_TASK: /* aka DCB_THREAD */
+ TRACE("Task(%04lx) !\n", dwCallBack);
+ PostThreadMessageA(dwCallBack, wMsg, (WPARAM)hDev, dwParam1);
+ break;
+ case DCB_FUNCTION:
+ TRACE("Function (32 bit) !\n");
+ ((LPDRVCALLBACK)dwCallBack)(hDev, wMsg, dwUser, dwParam1, dwParam2);
+ break;
+ case DCB_EVENT:
+ TRACE("Event(%08lx) !\n", dwCallBack);
+ SetEvent((HANDLE)dwCallBack);
+ break;
+ case 6: /* I would dub it DCB_MMTHREADSIGNAL */
+ /* this is an undocumented DCB_ value used for mmThreads
+ * loword of dwCallBack contains the handle of the lpMMThd block
+ * which dwSignalCount has to be incremented
+ */
+ if (pFnGetMMThread16)
+ {
+ WINE_MMTHREAD* lpMMThd = pFnGetMMThread16(LOWORD(dwCallBack));
+
+ TRACE("mmThread (%04x, %p) !\n", LOWORD(dwCallBack), lpMMThd);
+ /* same as mmThreadSignal16 */
+ InterlockedIncrement(&lpMMThd->dwSignalCount);
+ SetEvent(lpMMThd->hEvent);
+ /* some other stuff on lpMMThd->hVxD */
+ }
+ break;
+#if 0
+ case 4:
+ /* this is an undocumented DCB_ value for... I don't know */
+ break;
+#endif
+ default:
+ WARN("Unknown callback type %d\n", uFlags & DCB_TYPEMASK);
+ return FALSE;
+ }
+ TRACE("Done\n");
+ return TRUE;
+}
+
+/******************************************************************
+ * DRIVER_UnloadAll
+ *
+ *
+ */
+void DRIVER_UnloadAll(void)
+{
+ LPWINE_DRIVER lpDrv;
+ LPWINE_DRIVER lpNextDrv = NULL;
+ unsigned count = 0;
+
+ for (lpDrv = lpDrvItemList; lpDrv != NULL; lpDrv = lpNextDrv)
+ {
+ lpNextDrv = lpDrv->lpNextItem;
+ CloseDriver((HDRVR)lpDrv, 0, 0);
+ count++;
+ }
+ TRACE("Unloaded %u drivers\n", count);
+}
--- vendor/wine/dlls/winmm/current/joystick.c 2004-12-31 16:30:04 UTC (rev 12637)
+++ vendor/wine/dlls/winmm/current/joystick.c 2004-12-31 16:34:31 UTC (rev 12638)
@@ -0,0 +1,308 @@
+/* -*- 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "config.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#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 MAXJOYSTICK (JOYSTICKID2 + 1)
+#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 JOY_Sticks[MAXJOYSTICK];
+
+/**************************************************************************
+ * JOY_LoadDriver [internal]
+ */
+static BOOL JOY_LoadDriver(DWORD dwJoyID)
+{
+ if (dwJoyID >= MAXJOYSTICK)
+ return FALSE;
+ if (JOY_Sticks[dwJoyID].hDriver)
+ return TRUE;
+
+ JOY_Sticks[dwJoyID].hDriver = OpenDriverA("joystick.drv", 0, dwJoyID);
+ return (JOY_Sticks[dwJoyID].hDriver != 0);
+}
+
+/**************************************************************************
+ * JOY_Timer [internal]
+ */
+static void CALLBACK JOY_Timer(HWND hWnd, UINT wMsg, UINT wTimer, DWORD dwTime)
+{
+ int i;
+ WINE_JOYSTICK* joy;
+ JOYINFO ji;
+ LONG pos;
+ unsigned buttonChange;
+
+ for (i = 0; i < MAXJOYSTICK; i++) {
+ joy = &JOY_Sticks[i];
+
+ if (joy->hCapture != hWnd) continue;
+
+ joyGetPos(i, &ji);
+ pos = MAKELONG(ji.wXpos, ji.wYpos);
+
+ if (!joy->bChanged ||
+ abs(joy->ji.wXpos - ji.wXpos) > joy->threshold ||
+ abs(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 ||
+ abs(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;
+ }
+ }
+}
+
+/**************************************************************************
+ * joyGetNumDevs [WINMM.@]
+ */
+UINT WINAPI joyGetNumDevs(void)
+{
+ UINT ret = 0;
+ int i;
+
+ for (i = 0; i < MAXJOYSTICK; i++) {
+ if (JOY_LoadDriver(i)) {
+ ret += SendDriverMessage(JOY_Sticks[i].hDriver, JDD_GETNUMDEVS, 0L, 0L);
+ }
+ }
+ return ret;
+}
+
+/**************************************************************************
+ * joyGetDevCapsA [WINMM.@]
+ */
+MMRESULT WINAPI joyGetDevCapsA(UINT_PTR wID, LPJOYCAPSA lpCaps, UINT wSize)
+{
+ if (wID >= MAXJOYSTICK) return JOYERR_PARMS;
+ if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
+
+ lpCaps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */
+ lpCaps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */
+
+ return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETDEVCAPS, (DWORD)lpCaps, wSize);
+}
+
+/**************************************************************************
+ * joyGetDevCapsW [WINMM.@]
+ */
+MMRESULT WINAPI joyGetDevCapsW(UINT_PTR wID, LPJOYCAPSW lpCaps, UINT wSize)
+{
+ JOYCAPSA jca;
+ MMRESULT ret = joyGetDevCapsA(wID, &jca, sizeof(jca));
+
+ if (ret != JOYERR_NOERROR) return ret;
+ lpCaps->wMid = jca.wMid;
+ lpCaps->wPid = jca.wPid;
+ MultiByteToWideChar( CP_ACP, 0, jca.szPname, -1, lpCaps->szPname,
+ sizeof(lpCaps->szPname)/sizeof(WCHAR) );
+ lpCaps->wXmin = jca.wXmin;
+ lpCaps->wXmax = jca.wXmax;
+ lpCaps->wYmin = jca.wYmin;
+ lpCaps->wYmax = jca.wYmax;
+ lpCaps->wZmin = jca.wZmin;
+ lpCaps->wZmax = jca.wZmax;
+ lpCaps->wNumButtons = jca.wNumButtons;
+ lpCaps->wPeriodMin = jca.wPeriodMin;
+ lpCaps->wPeriodMax = jca.wPeriodMax;
+
+ if (wSize >= sizeof(JOYCAPSW)) { /* Win95 extensions ? */
+ lpCaps->wRmin = jca.wRmin;
+ lpCaps->wRmax = jca.wRmax;
+ lpCaps->wUmin = jca.wUmin;
+ lpCaps->wUmax = jca.wUmax;
+ lpCaps->wVmin = jca.wVmin;
+ lpCaps->wVmax = jca.wVmax;
+ lpCaps->wCaps = jca.wCaps;
+ lpCaps->wMaxAxes = jca.wMaxAxes;
+ lpCaps->wNumAxes = jca.wNumAxes;
+ lpCaps->wMaxButtons = jca.wMaxButtons;
+ MultiByteToWideChar( CP_ACP, 0, jca.szRegKey, -1, lpCaps->szRegKey,
+ sizeof(lpCaps->szRegKey)/sizeof(WCHAR) );
+ MultiByteToWideChar( CP_ACP, 0, jca.szOEMVxD, -1, lpCaps->szOEMVxD,
+ sizeof(lpCaps->szOEMVxD)/sizeof(WCHAR) );
+ }
+
+ return ret;
+}
+
+/**************************************************************************
+ * joyGetPosEx [WINMM.@]
+ */
+MMRESULT WINAPI joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo)
+{
+ TRACE("(%d, %p);\n", wID, lpInfo);
+
+ if (wID >= MAXJOYSTICK) 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(JOY_Sticks[wID].hDriver, JDD_GETPOSEX, (DWORD)lpInfo, 0L);
+}
+
+/**************************************************************************
+ * joyGetPos [WINMM.@]
+ */
+MMRESULT WINAPI joyGetPos(UINT wID, LPJOYINFO lpInfo)
+{
+ TRACE("(%d, %p);\n", wID, lpInfo);
+
+ if (wID >= MAXJOYSTICK) return JOYERR_PARMS;
+ if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
+
+ lpInfo->wXpos = 0;
+ lpInfo->wYpos = 0;
+ lpInfo->wZpos = 0;
+ lpInfo->wButtons = 0;
+
+ return SendDriverMessage(JOY_Sticks[wID].hDriver, JDD_GETPOS, (DWORD)lpInfo, 0L);
+}
+
+/**************************************************************************
+ * joyGetThreshold [WINMM.@]
+ */
+MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold)
+{
+ TRACE("(%04X, %p);\n", wID, lpThreshold);
+
+ if (wID >= MAXJOYSTICK) return JOYERR_PARMS;
+
+ *lpThreshold = JOY_Sticks[wID].threshold;
+ return JOYERR_NOERROR;
+}
+
+/**************************************************************************
+ * joyReleaseCapture [WINMM.@]
+ */
+MMRESULT WINAPI joyReleaseCapture(UINT wID)
+{
+ TRACE("(%04X);\n", wID);
+
+ if (wID >= MAXJOYSTICK) return JOYERR_PARMS;
+ if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
+ if (!JOY_Sticks[wID].hCapture) return JOYERR_NOCANDO;
+
+ KillTimer(JOY_Sticks[wID].hCapture, JOY_Sticks[wID].wTimer);
+ JOY_Sticks[wID].hCapture = 0;
+ JOY_Sticks[wID].wTimer = 0;
+
+ 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 >= MAXJOYSTICK || hWnd == 0) return JOYERR_PARMS;
+ if (wPeriod<JOY_PERIOD_MIN || wPeriod>JOY_PERIOD_MAX) return JOYERR_PARMS;
+ if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER;
+
+ if (JOY_Sticks[wID].hCapture || !IsWindow(hWnd))
+ return JOYERR_NOCANDO; /* FIXME: what should be returned ? */
+
+ if (joyGetPos(wID, &JOY_Sticks[wID].ji) != JOYERR_NOERROR)
+ return JOYERR_UNPLUGGED;
+
+ if ((JOY_Sticks[wID].wTimer = SetTimer(hWnd, 0, wPeriod, JOY_Timer)) == 0)
+ return JOYERR_NOCANDO;
+
+ JOY_Sticks[wID].hCapture = hWnd;
+ JOY_Sticks[wID].bChanged = bChanged;
+
+ return JOYERR_NOERROR;
+}
+
+/**************************************************************************
+ * joySetThreshold [WINMM.@]
+ */
+MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold)
+{
+ TRACE("(%04X, %d);\n", wID, wThreshold);
+
+ if (wID >= MAXJOYSTICK) return MMSYSERR_INVALPARAM;
+
+ JOY_Sticks[wID].threshold = wThreshold;
+
+ return JOYERR_NOERROR;
+}