Moved hardware related handling to dlls/winmm/joystick driver.
Got rid of joySendMessages() hack (now implementation with a timer).
diff --git a/dlls/winmm/joystick/joystick.c b/dlls/winmm/joystick/joystick.c
new file mode 100644
index 0000000..e1846fc
--- /dev/null
+++ b/dlls/winmm/joystick/joystick.c
@@ -0,0 +1,370 @@
+/* -*- tab-width: 8; c-basic-offset: 4 -*- */
+/*
+ * joystick functions
+ *
+ * Copyright 1997 Andreas Mohr
+ *
+ * nearly all joystick functions can be regarded as obsolete,
+ * as Linux (2.1.x) now supports extended joysticks
+ * with a completely new joystick driver interface
+ * new driver's docu says:
+ * "For backward compatibility the old interface is still included,
+ * but will be dropped in the future."
+ * Thus we should implement the new interface and at most keep the old
+ * routines for backward compatibility.
+ */
+
+/*
+ * Wolfgang Schwotzer
+ *
+ * 01/2000 added support for new joystick driver
+ *
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_LINUX_JOYSTICK_H
+#include <linux/joystick.h>
+#define JOYDEV "/dev/js%d"
+#endif
+#ifdef HAVE_SYS_ERRNO_H
+#include <sys/errno.h>
+#endif
+#include "windef.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "mmddk.h"
+#include "driver.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(joystick);
+
+#ifdef HAVE_LINUX_JOYSTICK_H
+
+#define MAXJOYSTICK (JOYSTICKID2 + 1)
+
+static struct dummy_struct* JSTCK_Dummy = NULL;
+
+/**************************************************************************
+ * JSTCK_drvOpen [internal]
+ */
+static DWORD JSTCK_drvOpen(LPSTR str)
+{
+ if (JSTCK_Dummy)
+ return 0;
+
+ /* I know, this is ugly, but who cares... */
+ JSTCK_Dummy = (struct dummy_struct*)1;
+ return 1;
+}
+
+/**************************************************************************
+ * JSTCK_drvClose [internal]
+ */
+static DWORD JSTCK_drvClose(DWORD dwDevID)
+{
+ if (JSTCK_Dummy) {
+ JSTCK_Dummy = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+struct js_status
+{
+ int buttons;
+ int x;
+ int y;
+};
+
+/**************************************************************************
+ * JSTCK_OpenDevice [internal]
+ */
+static int JSTCK_OpenDevice(WORD wID)
+{
+ char buf[20];
+ int flags;
+
+ if (wID >= MAXJOYSTICK) return -1;
+
+ sprintf(buf, JOYDEV, wID);
+#ifdef HAVE_LINUX_22_JOYSTICK_API
+ flags = O_RDONLY | O_NONBLOCK;
+#else
+ flags = O_RDONLY;
+#endif
+ return open(buf, flags);
+}
+
+/**************************************************************************
+ * JoyGetDevCaps [MMSYSTEM.102]
+ */
+static LONG JSTCK_GetDevCaps(DWORD dwDevID, LPJOYCAPSA lpCaps, DWORD dwSize)
+{
+#ifdef HAVE_LINUX_22_JOYSTICK_API
+ int dev;
+ char nrOfAxes;
+ char nrOfButtons;
+ char identString[MAXPNAMELEN];
+ int driverVersion;
+#endif
+
+ if (dwDevID >= MAXJOYSTICK) return MMSYSERR_NODRIVER;
+
+#ifdef HAVE_LINUX_22_JOYSTICK_API
+
+ if ((dev = JSTCK_OpenDevice(dwDevID)) < 0) return JOYERR_PARMS;
+ ioctl(dev, JSIOCGAXES, &nrOfAxes);
+ ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
+ ioctl(dev, JSIOCGVERSION, &driverVersion);
+ ioctl(dev, JSIOCGNAME(sizeof(identString)), &identString);
+ TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n",
+ driverVersion, identString, nrOfAxes, nrOfButtons);
+ lpCaps->wMid = MM_MICROSOFT;
+ lpCaps->wPid = MM_PC_JOYSTICK;
+ strncpy(lpCaps->szPname, identString, MAXPNAMELEN);
+ lpCaps->szPname[MAXPNAMELEN-1] = '\0';
+ lpCaps->wXmin = 0;
+ lpCaps->wXmax = 0xFFFF;
+ lpCaps->wYmin = 0;
+ lpCaps->wYmax = 0xFFFF;
+ lpCaps->wZmin = 0;
+ lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
+ lpCaps->wNumButtons = nrOfButtons;
+ if (dwSize == sizeof(JOYCAPSA)) {
+ /* since we supose ntOfAxes <= 6 in the following code, do it explicitely */
+ if (nrOfAxes > 6) nrOfAxes = 6;
+ /* complete 95 structure */
+ lpCaps->wRmin = 0;
+ lpCaps->wRmax = nrOfAxes >= 4 ? 0xFFFF : 0;
+ lpCaps->wUmin = 0;
+ lpCaps->wUmax = nrOfAxes >= 5 ? 0xFFFF : 0;
+ lpCaps->wVmin = 0;
+ lpCaps->wVmax = nrOfAxes >= 6 ? 0xFFFF : 0;
+ lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */
+ lpCaps->wNumAxes = nrOfAxes; /* nr of axes in use */
+ lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */
+ strcpy(lpCaps->szRegKey, "");
+ strcpy(lpCaps->szOEMVxD, "");
+ lpCaps->wCaps = 0;
+ switch(nrOfAxes) {
+ case 6: lpCaps->wCaps |= JOYCAPS_HASV;
+ case 5: lpCaps->wCaps |= JOYCAPS_HASU;
+ case 4: lpCaps->wCaps |= JOYCAPS_HASR;
+ case 3: lpCaps->wCaps |= JOYCAPS_HASZ;
+ /* FIXME: don't know how to detect for
+ JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
+ }
+ }
+ close(dev);
+
+#else
+ lpCaps->wMid = MM_MICROSOFT;
+ lpCaps->wPid = MM_PC_JOYSTICK;
+ strcpy(lpCaps->szPname, "WineJoy"); /* joystick product name */
+ lpCaps->wXmin = 0;
+ lpCaps->wXmax = 0xFFFF;
+ lpCaps->wYmin = 0;
+ lpCaps->wYmax = 0xFFFF;
+ lpCaps->wZmin = 0;
+ lpCaps->wZmax = 0;
+ lpCaps->wNumButtons = 2;
+ if (dwSize == sizeof(JOYCAPSA)) {
+ /* complete 95 structure */
+ lpCaps->wRmin = 0;
+ lpCaps->wRmax = 0;
+ lpCaps->wUmin = 0;
+ lpCaps->wUmax = 0;
+ lpCaps->wVmin = 0;
+ lpCaps->wVmax = 0;
+ lpCaps->wCaps = 0;
+ lpCaps->wMaxAxes = 2;
+ lpCaps->wNumAxes = 2;
+ lpCaps->wMaxButtons = 4;
+ strcpy(lpCaps->szRegKey,"");
+ strcpy(lpCaps->szOEMVxD,"");
+ }
+#endif
+
+ return JOYERR_NOERROR;
+}
+
+/**************************************************************************
+ * JSTCK_GetPos [internal]
+ */
+static LONG JSTCK_GetPosEx(DWORD dwDevID, LPJOYINFOEX lpInfo)
+{
+ int dev;
+#ifdef HAVE_LINUX_22_JOYSTICK_API
+ struct js_event ev;
+#else
+ struct js_status js;
+ int dev_stat;
+#endif
+
+ if ((dev = JSTCK_OpenDevice(dwDevID)) < 0) return JOYERR_PARMS;
+
+#ifdef HAVE_LINUX_22_JOYSTICK_API
+ /* After opening the device it's state can be
+ read with JS_EVENT_INIT flag */
+ while ((read(dev, &ev, sizeof(struct js_event))) > 0) {
+ if (ev.type == (JS_EVENT_AXIS | JS_EVENT_INIT)) {
+ switch (ev.number) {
+ case 0:
+ if (lpInfo->dwFlags & JOY_RETURNX)
+ lpInfo->dwXpos = ev.value + 32767;
+ break;
+ case 1:
+ if (lpInfo->dwFlags & JOY_RETURNY)
+ lpInfo->dwYpos = ev.value + 32767;
+ break;
+ case 2:
+ if (lpInfo->dwFlags & JOY_RETURNZ)
+ lpInfo->dwZpos = ev.value + 32767;
+ break;
+ case 3:
+ if (lpInfo->dwFlags & JOY_RETURNR)
+ lpInfo->dwRpos = ev.value + 32767;
+ case 4:
+ if (lpInfo->dwFlags & JOY_RETURNU)
+ lpInfo->dwUpos = ev.value + 32767;
+ case 5:
+ if (lpInfo->dwFlags & JOY_RETURNV)
+ lpInfo->dwVpos = ev.value + 32767;
+ break;
+ default:
+ FIXME("Unknown joystick event '%d'\n", ev.number);
+ }
+ } else if (ev.type == (JS_EVENT_BUTTON | JS_EVENT_INIT)) {
+ if (lpInfo->dwFlags & JOY_RETURNBUTTONS) {
+ if (ev.value) {
+ lpInfo->dwButtons |= (1 << ev.number);
+ /* FIXME: what to do for this field when
+ * multiple buttons are depressed ?
+ */
+ lpInfo->dwButtonNumber = ev.number + 1;
+ }
+ }
+ }
+ }
+ /* EAGAIN is returned when the queue is empty */
+ if (errno != EAGAIN) {
+ /* FIXME: error should not be ignored */
+ ERR("Error while reading joystick state (%d)\n", errno);
+ }
+#else
+ dev_stat = read(dev, &js, sizeof(js));
+ if (dev_stat != sizeof(js)) {
+ close(dev);
+ return JOYERR_UNPLUGGED; /* FIXME: perhaps wrong, but what should I return else ? */
+ }
+ js.x = js.x<<8;
+ js.y = js.y<<8;
+ if (lpInfo->dwFlags & JOY_RETURNX)
+ lpInfo->dwXpos = js.x; /* FIXME: perhaps multiply it somehow ? */
+ if (lpInfo->dwFlags & JOY_RETURNY)
+ lpInfo->dwYpos = js.y;
+ if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
+ lpInfo->dwButtons = js.buttons;
+#endif
+
+ close(dev);
+
+ TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x\n",
+ lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
+ lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
+ (unsigned int)lpInfo->dwButtons,
+ (unsigned int)lpInfo->dwFlags);
+
+ return JOYERR_NOERROR;
+}
+
+/**************************************************************************
+ * JSTCK_GetPos [internal]
+ */
+static LONG JSTCK_GetPos(DWORD dwDevID, LPJOYINFO lpInfo)
+{
+ JOYINFOEX ji;
+ LONG ret;
+
+ memset(&ji, 0, sizeof(ji));
+
+ ji.dwSize = sizeof(ji);
+ ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
+ ret = JSTCK_GetPosEx(dwDevID, &ji);
+ if (ret == JOYERR_NOERROR) {
+ lpInfo->wXpos = ji.dwXpos;
+ lpInfo->wYpos = ji.dwYpos;
+ lpInfo->wZpos = ji.dwZpos;
+ lpInfo->wButtons = ji.dwButtons;
+ }
+
+ return ret;
+}
+
+/**************************************************************************
+ * JSTCK_DriverProc [internal]
+ */
+LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
+ DWORD dwParam1, DWORD dwParam2)
+{
+ /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
+ /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
+
+ switch(wMsg) {
+ case DRV_LOAD: return 1;
+ case DRV_FREE: return 1;
+ case DRV_OPEN: return JSTCK_drvOpen((LPSTR)dwParam1);
+ case DRV_CLOSE: return JSTCK_drvClose(dwDevID);
+ case DRV_ENABLE: return 1;
+ case DRV_DISABLE: return 1;
+ case DRV_QUERYCONFIGURE: return 1;
+ case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1;
+ case DRV_INSTALL: return DRVCNF_RESTART;
+ case DRV_REMOVE: return DRVCNF_RESTART;
+
+ case JDD_GETNUMDEVS: return MAXJOYSTICK;
+ case JDD_GETDEVCAPS: return JSTCK_GetDevCaps(dwDevID, (LPJOYCAPSA)dwParam1, dwParam2);
+ case JDD_GETPOS: return JSTCK_GetPos(dwDevID, (LPJOYINFO)dwParam1);
+ case JDD_SETCALIBRATION:
+ case JDD_CONFIGCHANGED: return JOYERR_NOCANDO;
+ case JDD_GETPOSEX: return JSTCK_GetPosEx(dwDevID, (LPJOYINFOEX)dwParam1);
+ default:
+ return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
+ }
+}
+
+#else
+
+/**************************************************************************
+ * JSTCK_DriverProc [internal]
+ */
+LONG CALLBACK JSTCK_DriverProc(DWORD dwDevID, HDRVR hDriv, DWORD wMsg,
+ DWORD dwParam1, DWORD dwParam2)
+{
+ /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
+ /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
+
+ switch(wMsg) {
+ case DRV_LOAD:
+ case DRV_FREE:
+ case DRV_OPEN:
+ case DRV_CLOSE:
+ case DRV_ENABLE:
+ case DRV_DISABLE:
+ case DRV_QUERYCONFIGURE: return 0;
+ case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1;
+ case DRV_INSTALL: return DRVCNF_RESTART;
+ case DRV_REMOVE: return DRVCNF_RESTART;
+ default:
+ return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
+ }
+}
+
+#endif