Index: src/video/wincommon/SDL_lowvideo.h
===================================================================
--- src/video/wincommon/SDL_lowvideo.h	(revision 4067)
+++ src/video/wincommon/SDL_lowvideo.h	(working copy)
@@ -51,10 +51,13 @@
 /* Hidden "this" pointer for the video functions */
 #define _THIS	SDL_VideoDevice *this
 
+#define FULLSCREEN() \
+	((SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN)
+
 #define WINDIB_FULLSCREEN()						\
 (									\
 	SDL_VideoSurface &&						\
-	((SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) && \
+	FULLSCREEN() && \
 	(((SDL_VideoSurface->flags & SDL_OPENGL   ) == SDL_OPENGL    ) || \
 	((SDL_strcmp(this->name, "windib") == 0) || \
 	 (SDL_strcmp(this->name, "gapi") == 0))) \
@@ -62,13 +65,19 @@
 #define DDRAW_FULLSCREEN() 						\
 (									\
 	SDL_VideoSurface &&						\
-	((SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) && \
+	FULLSCREEN() && \
 	((SDL_VideoSurface->flags & SDL_OPENGL    ) != SDL_OPENGL    ) && \
 	(SDL_strcmp(this->name, "directx") == 0)				\
 )
 
-#define DINPUT_FULLSCREEN()	DDRAW_FULLSCREEN()
+#define DINPUT_FULLSCREEN() 						\
+(									\
+	FULLSCREEN() && \
+	(strcmp(this->name, "directx") == 0)				\
+)
 
+#define DINPUT() (strcmp(this->name, "directx") == 0)
+
 /* The main window -- and a function to set it for the audio */
 #ifdef _WIN32_WCE
 extern LPWSTR SDL_Appname;
Index: src/video/wincommon/SDL_sysevents.c
===================================================================
--- src/video/wincommon/SDL_sysevents.c	(revision 4067)
+++ src/video/wincommon/SDL_sysevents.c	(working copy)
@@ -335,7 +335,6 @@
 {
 	SDL_VideoDevice *this = current_video;
 	static int mouse_pressed = 0;
-	static int in_window = 0;
 #ifdef WMMSG_DEBUG
 	fprintf(stderr, "Received windows message:  ");
 	if ( msg > MAX_WMMSG ) {
@@ -411,62 +410,41 @@
 		break;
 
 		case WM_MOUSEMOVE: {
-			
-			/* Mouse is handled by DirectInput when fullscreen */
-			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
-				Sint16 x, y;
 
-				/* mouse has entered the window */
-				if ( ! in_window ) {
 #ifdef WM_MOUSELEAVE
+			/* No need to handle SDL_APPMOUSEFOCUS when fullscreen */
+			if ( SDL_VideoSurface && !FULLSCREEN() ) {
+				/* mouse has entered the window */
+
+				if ( !(SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
 					TRACKMOUSEEVENT tme;
 
 					tme.cbSize = sizeof(tme);
 					tme.dwFlags = TME_LEAVE;
 					tme.hwndTrack = SDL_Window;
 					_TrackMouseEvent(&tme);
+				}
+			}
 #endif /* WM_MOUSELEAVE */
-					in_window = TRUE;
 
-					posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
-				}
+			/* Mouse motion is handled in DIB_PumpEvents or
+			 * DX5_PumpEvents, depending on the video driver
+			 * in use */
 
-				/* mouse has moved within the window */
-				x = LOWORD(lParam);
-				y = HIWORD(lParam);
-				if ( mouse_relative ) {
-					POINT center;
-					center.x = (SDL_VideoSurface->w/2);
-					center.y = (SDL_VideoSurface->h/2);
-					x -= (Sint16)center.x;
-					y -= (Sint16)center.y;
-					if ( x || y ) {
-						ClientToScreen(SDL_Window, &center);
-						SetCursorPos(center.x, center.y);
-						posted = SDL_PrivateMouseMotion(0, 1, x, y);
-					}
-				} else {
-#ifdef _WIN32_WCE
-					if (SDL_VideoSurface)
-						GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y);
-#endif
-					posted = SDL_PrivateMouseMotion(0, 0, x, y);
-				}
-			}
+			posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
 		}
 		return(0);
 
 #ifdef WM_MOUSELEAVE
 		case WM_MOUSELEAVE: {
 
-			/* Mouse is handled by DirectInput when fullscreen */
-			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
+			/* No need to handle SDL_APPMOUSEFOCUS when fullscreen */
+			if ( SDL_VideoSurface && !FULLSCREEN() ) {
 				/* mouse has left the window */
 				/* or */
 				/* Elvis has left the building! */
 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
 			}
-			in_window = FALSE;
 		}
 		return(0);
 #endif /* WM_MOUSELEAVE */
@@ -480,7 +458,7 @@
 		case WM_XBUTTONDOWN:
 		case WM_XBUTTONUP: {
 			/* Mouse is handled by DirectInput when fullscreen */
-			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
+			if ( SDL_VideoSurface && ! DINPUT() ) {
 				WORD xbuttonval = 0;
 				Sint16 x, y;
 				Uint8 button, state;
@@ -544,20 +522,8 @@
 						mouse_pressed = 0;
 					}
 				}
-				if ( mouse_relative ) {
-				/*	RJR: March 28, 2000
-					report internal mouse position if in relative mode */
-					x = 0; y = 0;
-				} else {
-					x = (Sint16)LOWORD(lParam);
-					y = (Sint16)HIWORD(lParam);
-#ifdef _WIN32_WCE
-					if (SDL_VideoSurface)
-						GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y);
-#endif
-				}
 				posted = SDL_PrivateMouseButton(
-							state, button, x, y);
+							state, button, 0, 0);
 
 				/*
 				 * MSDN says:
@@ -578,7 +544,7 @@
 
 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
 		case WM_MOUSEWHEEL: 
-			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
+			if ( SDL_VideoSurface && ! DINPUT() ) {
 				int move = (short)HIWORD(wParam);
 				if ( move ) {
 					Uint8 button;
Index: src/video/wincommon/SDL_sysmouse.c
===================================================================
--- src/video/wincommon/SDL_sysmouse.c	(revision 4067)
+++ src/video/wincommon/SDL_sysmouse.c	(working copy)
@@ -188,8 +188,7 @@
 {
 	POINT mouse_pos;
 
-	/* The fullscreen cursor must be done in software with DirectInput */
-	if ( !this->screen || DDRAW_FULLSCREEN() ) {
+	if ( !this->screen ) {
 		return(0);
 	}
 
@@ -208,15 +207,20 @@
 
 void WIN_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
 {
-	if ( DDRAW_FULLSCREEN() ) {
-		SDL_PrivateMouseMotion(0, 0, x, y);
-	} else if ( mouse_relative) {
+	if ( mouse_relative) {
 		/*	RJR: March 28, 2000
 			leave physical cursor at center of screen if
 			mouse hidden and grabbed */
 		SDL_PrivateMouseMotion(0, 0, x, y);
 	} else {
 		POINT pt;
+
+		/* With DirectInput the position doesn't follow
+		 * the cursor, so it is set manually */
+		if ( DINPUT() ) {
+			SDL_PrivateMouseMotion(0, 0, x, y);
+		}
+
 		pt.x = x;
 		pt.y = y;
 		ClientToScreen(SDL_Window, &pt);
@@ -227,20 +231,15 @@
 /* Update the current mouse state and position */
 void WIN_UpdateMouse(_THIS)
 {
-	RECT rect;
 	POINT pt;
 
-	if ( ! DDRAW_FULLSCREEN() ) {
-		GetClientRect(SDL_Window, &rect);
-		GetCursorPos(&pt);
-		MapWindowPoints(NULL, SDL_Window, &pt, 1);
-		if (PtInRect(&rect, pt) && (WindowFromPoint(pt) == SDL_Window)){
-			SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
-			SDL_PrivateMouseMotion(0,0, (Sint16)pt.x, (Sint16)pt.y);
-		} else {
-			SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
-		}
-	}
+	/* Always unset SDL_APPMOUSEFOCUS to give the WM_MOUSEMOVE event
+	 * handler a chance to install a TRACKMOUSEEVENT */
+	SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
+
+	GetCursorPos(&pt);
+	ScreenToClient(SDL_Window, &pt);
+	SDL_PrivateMouseMotion(0,0, (Sint16)pt.x, (Sint16)pt.y);
 }
 
 /* Check to see if we need to enter or leave mouse relative mode */
Index: src/video/windib/SDL_dibevents.c
===================================================================
--- src/video/windib/SDL_dibevents.c	(revision 4067)
+++ src/video/windib/SDL_dibevents.c	(working copy)
@@ -262,6 +262,36 @@
 	return(DefWindowProc(hwnd, msg, wParam, lParam));
 }
 
+static void DIB_GenerateMouseMotionEvent(void)
+{
+	extern int mouse_relative;
+	extern int posted;
+
+	POINT mouse;
+	GetCursorPos( &mouse );
+
+	if ( mouse_relative ) {
+		POINT center;
+		center.x = (SDL_VideoSurface->w/2);
+		center.y = (SDL_VideoSurface->h/2);
+		ClientToScreen(SDL_Window, &center);
+
+		mouse.x -= (Sint16)center.x;
+		mouse.y -= (Sint16)center.y;
+		if ( mouse.x || mouse.y ) {
+			SetCursorPos(center.x, center.y);
+			posted = SDL_PrivateMouseMotion(0, 1, mouse.x, mouse.y);
+		}
+	} else if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) {
+		ScreenToClient(SDL_Window, &mouse);
+#ifdef _WIN32_WCE
+		if (SDL_VideoSurface)
+			GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &mouse.x, &mouse.y);
+#endif
+		posted = SDL_PrivateMouseMotion(0, 0, mouse.x, mouse.y);
+	}
+}
+
 void DIB_PumpEvents(_THIS)
 {
 	MSG msg;
@@ -271,6 +301,10 @@
 			DispatchMessage(&msg);
 		}
 	}
+
+	if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
+		DIB_GenerateMouseMotionEvent( );
+	}
 }
 
 static HKL hLayoutUS = NULL;
@@ -494,7 +528,7 @@
 		Uint16	wchars[2];
 
 		GetKeyboardState(keystate);
-		if (SDL_ToUnicode((UINT)vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1)
+		if (SDL_ToUnicode((UINT)vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0)
 		{
 			keysym->unicode = wchars[0];
 		}
Index: src/video/windx5/SDL_dx5events.c
===================================================================
--- src/video/windx5/SDL_dx5events.c	(revision 4067)
+++ src/video/windx5/SDL_dx5events.c	(working copy)
@@ -143,9 +143,14 @@
 		(DISCL_FOREGROUND|DISCL_NONEXCLUSIVE),
 		(DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), handle_keyboard },
 	{ "mouse",
-		&GUID_SysMouse, &c_dfDIMouse,
+		&GUID_SysMouse,
+#if DIRECTINPUT_VERSION >= 0x700
+		&c_dfDIMouse2,
+#else
+		&c_dfDIMouse,
+#endif
 		(DISCL_FOREGROUND|DISCL_NONEXCLUSIVE),
-		(DISCL_FOREGROUND|DISCL_EXCLUSIVE), handle_mouse },
+		(DISCL_FOREGROUND|DISCL_NONEXCLUSIVE), handle_mouse },
 	{ NULL, NULL, NULL, 0, 0, NULL }
 };
 	
@@ -285,6 +290,76 @@
 		}
 	}
 }
+
+static void post_mouse_motion(int relative, Sint16 x, Sint16 y)
+{
+	extern int mouse_relative;
+
+	if ( SDL_GetAppState() & (SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS) ==
+		(SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS) ) {
+		posted = SDL_PrivateMouseMotion(
+			0, relative, x, y);
+
+		if ( !mouse_relative ) {
+			/* As DirectInput reads raw device coordinates, it has no notion of
+			 * cursors or absolute position. We must assume responsibility for
+			 * keeping track of this. */
+			int current_x, current_y;
+			POINT cursor;
+			RECT trap;
+			RECT window;
+			int at_edge;
+
+			/* Get the current cursor position */
+			SDL_GetMouseState(&current_x, &current_y);
+			cursor.x = current_x;
+			cursor.y = current_y;
+			ClientToScreen(SDL_Window, &cursor);
+
+			/* Construct a 1 pixel square RECT that is used to confine the cursor
+			 * pointer to a specific pixel using ClipCursor. This is used in
+			 * preference to SetCursorPos as it avoids the cursor jumping around as
+			 * both the OS and SDL attempt to move it simultaneously. */
+			trap.left = cursor.x;
+			trap.top = cursor.y;
+			trap.right = cursor.x + 1;
+			trap.bottom = cursor.y + 1;
+
+			GetClientRect(SDL_Window, &window);
+			window.right -= window.left; window.left = 0;
+			window.bottom -= window.top; window.top = 0;
+
+			/* As we're assuming control over the cursor, we need to know when to
+			 * relinquish control of it back to the operating system. This is when
+			 * the cursor reaches the edge of the window. */
+			at_edge = (current_x == window.left) ||
+				(current_x == (window.right - 1)) ||
+				(current_y == window.top) ||
+				(current_y == (window.bottom - 1));
+
+			if ( at_edge ) {
+				ClipCursor(NULL);
+			} else {
+				ClipCursor(&trap);
+			}
+		} else {
+			/* When in relative mode, warp the OS's idea of where the cursor is to
+			 * the center of the screen. This isn't really necessary as DirectInput
+			 * reads from the hardware itself, but in case things go wrong, the
+			 * cursor will be left in a sensible place. */
+			POINT center;
+			center.x = (SDL_VideoSurface->w/2);
+			center.y = (SDL_VideoSurface->h/2);
+			ClientToScreen(SDL_Window, &center);
+			SetCursorPos(center.x, center.y);
+		}
+	} else {
+		/* No window or mouse focus, control is lost */
+		mouse_lost = 1;
+		ClipCursor(NULL);
+	}
+}
+
 static void handle_mouse(const int numevents, DIDEVICEOBJECTDATA *ptrbuf)
 {
 	int i;
@@ -298,14 +373,8 @@
 		return;
 	}
 
-	/* If we are in windowed mode, Windows is taking care of the mouse */
-	if (  (SDL_PublicSurface->flags & SDL_OPENGL) ||
-	     !(SDL_PublicSurface->flags & SDL_FULLSCREEN) ) {
-		return;
-	}
-
 	/* If the mouse was lost, regain some sense of mouse state */
-	if ( mouse_lost ) {
+	if ( mouse_lost && (SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
 		POINT mouse_pos;
 		Uint8 old_state;
 		Uint8 new_state;
@@ -313,14 +382,17 @@
 		/* Set ourselves up with the current cursor position */
 		GetCursorPos(&mouse_pos);
 		ScreenToClient(SDL_Window, &mouse_pos);
-		posted = SDL_PrivateMouseMotion(0, 0,
-				(Sint16)mouse_pos.x, (Sint16)mouse_pos.y);
+		post_mouse_motion( 0, (Sint16)mouse_pos.x, (Sint16)mouse_pos.y);
 
 		/* Check for mouse button changes */
 		old_state = SDL_GetMouseState(NULL, NULL);
 		new_state = 0;
 		{ /* Get the new DirectInput button state for the mouse */
+#if DIRECTINPUT_VERSION >= 0x700
+			DIMOUSESTATE2 distate;
+#else
 			DIMOUSESTATE distate;
+#endif
 			HRESULT result;
 
 			result=IDirectInputDevice2_GetDeviceState(SDL_DIdev[1],
@@ -341,14 +413,13 @@
 		for ( i=0; i<8; ++i ) {
 			if ( (old_state&0x01) != (new_state&0x01) ) {
 				button = (Uint8)(i+1);
-				/* Button #2 on two button mice is button 3
-				   (the middle button is button 2)
-				 */
-				if ( button == 2 ) {
-					button = 3;
-				} else
-				if ( button == 3 ) {
-					button = 2;
+				/* Map DI button numbers to SDL */
+				switch ( button ) {
+					case 2: button = SDL_BUTTON_RIGHT; break;
+					case 3: button = SDL_BUTTON_MIDDLE; break;
+					case 4: button = SDL_BUTTON_X1; break;
+					case 5: button = SDL_BUTTON_X2; break;
+					default: break;
 				}
 				if ( new_state & 0x01 ) {
 					/* Grab mouse so we get mouse-up */
@@ -387,8 +458,7 @@
 			case DIMOFS_X:
 				if ( timestamp != ptrbuf[i].dwTimeStamp ) {
 					if ( xrel || yrel ) {
-						posted = SDL_PrivateMouseMotion(
-								0, 1, xrel, yrel);
+						post_mouse_motion(1, xrel, yrel);
 						xrel = 0;
 						yrel = 0;
 					}
@@ -399,8 +469,7 @@
 			case DIMOFS_Y:
 				if ( timestamp != ptrbuf[i].dwTimeStamp ) {
 					if ( xrel || yrel ) {
-						posted = SDL_PrivateMouseMotion(
-								0, 1, xrel, yrel);
+						post_mouse_motion(1, xrel, yrel);
 						xrel = 0;
 						yrel = 0;
 					}
@@ -410,8 +479,7 @@
 				break;
 			case DIMOFS_Z:
 				if ( xrel || yrel ) {
-					posted = SDL_PrivateMouseMotion(
-							0, 1, xrel, yrel);
+					post_mouse_motion(1, xrel, yrel);
 					xrel = 0;
 					yrel = 0;
 				}
@@ -429,22 +497,26 @@
 			case DIMOFS_BUTTON1:
 			case DIMOFS_BUTTON2:
 			case DIMOFS_BUTTON3:
+#if DIRECTINPUT_VERSION >= 0x700
+			case DIMOFS_BUTTON4:
+			case DIMOFS_BUTTON5:
+			case DIMOFS_BUTTON6:
+			case DIMOFS_BUTTON7:
+#endif
 				if ( xrel || yrel ) {
-					posted = SDL_PrivateMouseMotion(
-							0, 1, xrel, yrel);
+					post_mouse_motion(1, xrel, yrel);
 					xrel = 0;
 					yrel = 0;
 				}
 				timestamp = 0;
 				button = (Uint8)(ptrbuf[i].dwOfs-DIMOFS_BUTTON0)+1;
-				/* Button #2 on two button mice is button 3
-				   (the middle button is button 2)
-				 */
-				if ( button == 2 ) {
-					button = 3;
-				} else
-				if ( button == 3 ) {
-					button = 2;
+				/* Map DI button numbers to SDL */
+				switch ( button ) {
+					case 2: button = SDL_BUTTON_RIGHT; break;
+					case 3: button = SDL_BUTTON_MIDDLE; break;
+					case 4: button = SDL_BUTTON_X1; break;
+					case 5: button = SDL_BUTTON_X2; break;
+					default: break;
 				}
 				if ( ptrbuf[i].dwData & 0x80 ) {
 					/* Grab mouse so we get mouse-up */
@@ -471,7 +543,7 @@
 		}
 	}
 	if ( xrel || yrel ) {
-		posted = SDL_PrivateMouseMotion( 0, 1, xrel, yrel);
+		post_mouse_motion(1, xrel, yrel);
 	}
 }
 
@@ -516,10 +588,7 @@
 
 		/* The keyboard is handled via DirectInput */
 		case WM_SYSKEYUP:
-		case WM_SYSKEYDOWN: {
-			/* Pass syskey to DefWindwoProc (ALT-F4, etc.) */
-		}
-		break;
+		case WM_SYSKEYDOWN:
 		case WM_KEYUP:
 		case WM_KEYDOWN: {
 			/* Ignore windows keyboard messages */;
@@ -840,7 +909,7 @@
 		keysym->unicode = vkey;
 #else
 		GetKeyboardState(keystate);
-		if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) == 1)
+		if (SDL_ToUnicode(vkey, scancode, keystate, wchars, sizeof(wchars)/sizeof(wchars[0]), 0) > 0)
 		{
 			keysym->unicode = wchars[0];
 		}
Index: src/video/windx5/directx.h
===================================================================
--- src/video/windx5/directx.h	(revision 4067)
+++ src/video/windx5/directx.h	(working copy)
@@ -72,7 +72,7 @@
 /* We need these defines to mark what version of DirectX API we use */
 #define DIRECTDRAW_VERSION  0x0700
 #define DIRECTSOUND_VERSION 0x0500
-#define DIRECTINPUT_VERSION 0x0500
+#define DIRECTINPUT_VERSION 0x0700
 
 #ifdef __GNUC__
 #define NONAMELESSUNION
@@ -81,4 +81,20 @@
 #include <dsound.h>
 #include <dinput.h>
 
+#if DIRECTINPUT_VERSION >= 0x0700 && !defined(DIMOFS_BUTTON4)
+typedef struct _DIMOUSESTATE2 {
+    LONG    lX;
+    LONG    lY;
+    LONG    lZ;
+    BYTE    rgbButtons[8];
+} DIMOUSESTATE2, *LPDIMOUSESTATE2;
+
+#define DIMOFS_BUTTON4 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 4)
+#define DIMOFS_BUTTON5 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 5)
+#define DIMOFS_BUTTON6 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 6)
+#define DIMOFS_BUTTON7 (FIELD_OFFSET(DIMOUSESTATE2, rgbButtons) + 7)
+
+extern const DIDATAFORMAT c_dfDIMouse2;
+#endif
+
 #endif /* _directx_h */
Index: configure.in
===================================================================
--- configure.in	(revision 4067)
+++ configure.in	(working copy)
@@ -2442,7 +2442,7 @@
         # Set up the system libraries we need
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -luser32 -lgdi32 -lwinmm"
         if test x$have_directx = xyes; then
-            EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldxguid"
+            EXTRA_LDFLAGS="$EXTRA_LDFLAGS -ldxguid -ldinput8"
         fi
         # The Win32 platform requires special setup
         SOURCES="$SOURCES $srcdir/src/main/win32/*.rc"
