Fixed Linux 2.2 event API code.

diff --git a/dlls/winmm/joystick/joystick.c b/dlls/winmm/joystick/joystick.c
index 5c5bbdf..286044e 100644
--- a/dlls/winmm/joystick/joystick.c
+++ b/dlls/winmm/joystick/joystick.c
@@ -3,6 +3,8 @@
  * joystick functions
  *
  * Copyright 1997 Andreas Mohr
+ * Copyright 2000 Wolfgang Schwotzer
+ * Copyright 2002 David Hagood
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,13 +32,6 @@
  * routines for backward compatibility.
  */
 
-/*
- * Wolfgang Schwotzer
- *
- *    01/2000    added support for new joystick driver
- *
- */
-
 #include "config.h"
 
 #ifdef HAVE_UNISTD_H
@@ -73,6 +68,24 @@
 typedef struct tagWINE_JSTCK {
     int		joyIntf;
     int		in_use;
+    /* Some extra info we need to make this acutaly work under the
+       Linux 2.2 event api.
+       First of all, we cannot keep closing and reopening the device file -
+       that blows away the state of the stick device, and we lose events. So, we
+       need to open the low-level device once, and close it when we are done.
+
+       Secondly, the event API only gives us what's changed. However, Windows apps
+       want the whole state every time, so we have to cache the data.
+    */
+
+    int         dev; /* Linux level device file descriptor */
+    int         x;
+    int         y;
+    int         z;
+    int         r;
+    int         u;
+    int         v;
+    int         buttons;
 } WINE_JSTCK;
 
 static	WINE_JSTCK	JSTCK_Data[MAXJOYSTICK];
@@ -116,6 +129,11 @@
     if (jstck == NULL)
 	return 0;
     jstck->in_use = 0;
+    if (jstck->dev > 0)
+    {
+       close(jstck->dev);
+       jstck->dev = 0;
+    }
     return 1;
 }
 
@@ -134,13 +152,16 @@
     char	buf[20];
     int		flags;
 
+    if (jstick->dev > 0)
+      return jstick->dev;
+
     sprintf(buf, JOYDEV, jstick->joyIntf);
 #ifdef HAVE_LINUX_22_JOYSTICK_API
     flags = O_RDONLY | O_NONBLOCK;
 #else
     flags = O_RDONLY;
 #endif
-    return open(buf, flags);
+    return (jstick->dev = open(buf, flags));
 }
 
 /**************************************************************************
@@ -161,7 +182,6 @@
 	return MMSYSERR_NODRIVER;
 
 #ifdef HAVE_LINUX_22_JOYSTICK_API
-
     if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
     ioctl(dev, JSIOCGAXES, &nrOfAxes);
     ioctl(dev, JSIOCGBUTTONS, &nrOfButtons);
@@ -179,7 +199,19 @@
     lpCaps->wYmax = 0xFFFF;
     lpCaps->wZmin = 0;
     lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0;
+#ifdef BODGE_THE_HAT
+    /* HalfLife won't allow you to map an axis event to things like
+       "next weapon" and "use". Linux reports the hat on my stick as
+       axis U and V. So, IFF BODGE_THE_HAT is defined, lie through our
+       teeth and say we have 32 buttons, and we will map the axises to
+       the high buttons. Really, perhaps this should be a registry entry,
+       or even a parameter to the Linux joystick driver (which would completely
+       remove the need for this.)
+    */
+    lpCaps->wNumButtons = 32;
+#else
     lpCaps->wNumButtons = nrOfButtons;
+#endif
     if (dwSize == sizeof(JOYCAPSA)) {
 	/* since we suppose ntOfAxes <= 6 in the following code, do it explicitly */
 	if (nrOfAxes > 6) nrOfAxes = 6;
@@ -205,8 +237,6 @@
 	       JOYCAPS_HASPOV, JOYCAPS_POV4DIR, JOYCAPS_POVCTS */
 	}
     }
-    close(dev);
-
 #else
     lpCaps->wMid = MM_MICROSOFT;
     lpCaps->wPid = MM_PC_JOYSTICK;
@@ -258,46 +288,41 @@
     if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS;
 
 #ifdef HAVE_LINUX_22_JOYSTICK_API
-    /* After opening the device, its 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)) {
+	if (ev.type == (JS_EVENT_AXIS)) {
 	    switch (ev.number) {
 	    case 0:
-		if (lpInfo->dwFlags & JOY_RETURNX)
-		    lpInfo->dwXpos   = ev.value + 32767;
+		jstck->x = ev.value;
 		break;
 	    case 1:
-		if (lpInfo->dwFlags & JOY_RETURNY)
-		    lpInfo->dwYpos   = ev.value + 32767;
+		jstck->y = ev.value;
 		break;
 	    case 2:
-		if (lpInfo->dwFlags & JOY_RETURNZ)
-		    lpInfo->dwZpos   = ev.value + 32767;
+		jstck->z = ev.value;
 		break;
 	    case 3:
-		if (lpInfo->dwFlags & JOY_RETURNR)
-		    lpInfo->dwRpos   = ev.value + 32767;
+		jstck->r = ev.value;
+		break;
 	    case 4:
-		if (lpInfo->dwFlags & JOY_RETURNU)
-		    lpInfo->dwUpos   = ev.value + 32767;
+		jstck->u = ev.value;
+		break;
 	    case 5:
-		if (lpInfo->dwFlags & JOY_RETURNV)
-		    lpInfo->dwVpos   = ev.value + 32767;
+		jstck->v = ev.value;
 		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);
+	} else if (ev.type == (JS_EVENT_BUTTON)) {
+	    if (ev.value) {
+		    jstck->buttons |= (1 << ev.number);
 		    /* FIXME: what to do for this field when
 		     * multiple buttons are depressed ?
 		     */
-		    lpInfo->dwButtonNumber = ev.number + 1;
+		    if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
+                       lpInfo->dwButtonNumber = ev.number + 1;
 		}
-	    }
+             else
+               jstck->buttons  &= ~(1 << ev.number);
 	}
     }
     /* EAGAIN is returned when the queue is empty */
@@ -305,10 +330,43 @@
 	/* FIXME: error should not be ignored */
 	ERR("Error while reading joystick state (%s)\n", strerror(errno));
     }
+    /* Now, copy the cached values into Window's structure... */
+    if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
+       lpInfo->dwButtons = jstck->buttons;
+    if (lpInfo->dwFlags & JOY_RETURNX)
+       lpInfo->dwXpos   = jstck->x + 32767;
+    if (lpInfo->dwFlags & JOY_RETURNY)
+       lpInfo->dwYpos   = jstck->y + 32767;
+    if (lpInfo->dwFlags & JOY_RETURNZ)
+       lpInfo->dwZpos   = jstck->z + 32767;
+    if (lpInfo->dwFlags & JOY_RETURNR)
+       lpInfo->dwRpos   = jstck->r + 32767;
+    #ifdef BODGE_THE_HAT
+    else if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
+    {
+         if (jstck->r > 0)
+            lpInfo->dwButtons |= 1<<7;
+         else if (jstck->r < 0)
+            lpInfo->dwButtons |= 1<<8;
+    }
+    #endif
+    if (lpInfo->dwFlags & JOY_RETURNU)
+	lpInfo->dwUpos   = jstck->u + 32767;
+    #ifdef BODGE_THE_HAT
+    else if (lpInfo->dwFlags & JOY_RETURNBUTTONS)
+    {
+       if (jstck->u > 0)
+          lpInfo->dwButtons |= 1<<9;
+        else if (jstck->u < 0)
+          lpInfo->dwButtons |= 1<<10;
+    }
+    #endif
+    if (lpInfo->dwFlags & JOY_RETURNV)
+       lpInfo->dwVpos   = jstck->v + 32767;
+
 #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;
@@ -321,13 +379,13 @@
 	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",
+    TRACE("x: %ld, y: %ld, z: %ld, r: %ld, u: %ld, v: %ld, buttons: 0x%04x, flags: 0x%04x (fd %d)\n",
 	  lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos,
 	  lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos,
 	  (unsigned int)lpInfo->dwButtons,
-	  (unsigned int)lpInfo->dwFlags);
+	  (unsigned int)lpInfo->dwFlags,
+          dev
+         );
 
     return JOYERR_NOERROR;
 }