diff --git a/src/Makefile.am b/src/Makefile.am
index 1e774cbaa..dacf2b803 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -38,6 +38,7 @@ supertuxkart_SOURCES =             main.cpp  			\
 	music_ogg.cpp	   	   music_ogg.hpp            	\
 	sfx_openal.cpp             sfx_openal.hpp              	\
 	utils.cpp		   utils.hpp                	\
+	inputmap.cpp		   inputmap.hpp			\
 	isect.cpp		   isect.hpp                	\
 	track.cpp		   track.hpp                	\
 	herring.cpp 		   herring.hpp              	\
diff --git a/src/gui/base_gui.cpp b/src/gui/base_gui.cpp
index 89b9e45df..3e8f1826e 100644
--- a/src/gui/base_gui.cpp
+++ b/src/gui/base_gui.cpp
@@ -31,19 +31,6 @@ void BaseGUI::input(InputType type, int id0, int  id1, int id2, int value)
     case IT_KEYBOARD:
         inputKeyboard(id0, value);
         break;
-
-    case IT_MOUSEMOTION:
-        widgetSet->pulse(widgetSet->point(m_menu_id, id0, id1), 1.2f);
-
-#ifdef  ALT_MOUSE_HANDLING
-        if (id0 == 1 && value)
-            if (id1 == AD_NEGATIVE)
-                inputKeyboard(SDLK_UP, 1);
-            else
-                inputKeyboard(SDLK_DOWN, 1);
-#endif
-        break;
-
     case IT_MOUSEBUTTON:
       if (!value) // Act on button release only.
         switch (id0)
@@ -131,6 +118,12 @@ void BaseGUI::inputKeyboard(int key, int pressed)
         break;
     }   // switch
 }   // inputKeyboard
+//-----------------------------------------------------------------------------
+void
+BaseGUI::inputPointer(int x, int y)
+{
+  widgetSet->pulse(widgetSet->point(m_menu_id, x, y), 1.2f);
+}
 
 //-----------------------------------------------------------------------------
 void BaseGUI::update(float dt)
diff --git a/src/gui/base_gui.hpp b/src/gui/base_gui.hpp
index e7aa5207f..c8d79992b 100644
--- a/src/gui/base_gui.hpp
+++ b/src/gui/base_gui.hpp
@@ -33,6 +33,9 @@ public:
 
     virtual void input(InputType type, int id0, int id1, int id2, int value);
     virtual void inputKeyboard(int key, int pressed);
+
+    void inputPointer(int x, int y);
+
     void  TimeToString(const float time, char *s);
 protected:
 
diff --git a/src/gui/menu_manager.cpp b/src/gui/menu_manager.cpp
index 723c26991..fab724b11 100644
--- a/src/gui/menu_manager.cpp
+++ b/src/gui/menu_manager.cpp
@@ -46,6 +46,7 @@
 #include "credits_menu.hpp"
 #include "grand_prix_select.hpp"
 #include "sound_manager.hpp"
+#include "sdldrv.hpp"
 
 MenuManager* menu_manager= new MenuManager();
 
@@ -93,7 +94,11 @@ void MenuManager::update()
 
     if (m_handled_size != m_menu_stack.size())
     {
-        if(m_current_menu==m_RaceGUI) m_RaceGUI=0;
+        if(m_current_menu==m_RaceGUI)
+        {
+          m_RaceGUI = 0;
+          drv_showPointer();
+        }
 
         delete m_current_menu;
         m_current_menu= NULL;
@@ -132,6 +137,7 @@ void MenuManager::update()
                 m_current_menu= new NumPlayers();
                 break;
             case MENUID_RACE:
+                drv_hidePointer();
                 m_current_menu = new RaceGUI();
                 m_RaceGUI      = m_current_menu;
                 break;
diff --git a/src/gui/options.cpp b/src/gui/options.cpp
index 3b1f68ab5..70e9047c2 100644
--- a/src/gui/options.cpp
+++ b/src/gui/options.cpp
@@ -37,14 +37,16 @@ Options::Options()
     widgetSet -> space(m_menu_id);
     widgetSet -> label(m_menu_id, _("Options"),   GUI_LRG, GUI_ALL, 0, 0);
     widgetSet -> start(m_menu_id, _("Player Config"),  GUI_MED, WTOK_CONTROLS);
+
+#ifndef WIN32
     // Don't display the fullscreen menu when called from within the race.
+    // (Windows only)
     // The fullscreen mode will reload all textures, reload the models,
     // ... basically creating a big mess!!  (and all of this only thanks
     // to windows, who discards all textures, ...)
-    if(!menu_manager->isSomewhereOnStack(MENUID_RACE))
-    {
-        widgetSet -> state(m_menu_id, _("Display"),   GUI_MED, WTOK_DISPLAY);
-    }
+    widgetSet -> state(m_menu_id, _("Display"),   GUI_MED, WTOK_DISPLAY);
+#endif
+
     widgetSet -> state(m_menu_id, _("Sound"),     GUI_MED, WTOK_SOUND);
     widgetSet -> space(m_menu_id);
     widgetSet -> state(m_menu_id, _("Press <ESC> to go back"), GUI_SML, WTOK_BACK);
diff --git a/src/gui/player_controls.cpp b/src/gui/player_controls.cpp
index c20f67314..20c9dbcc8 100644
--- a/src/gui/player_controls.cpp
+++ b/src/gui/player_controls.cpp
@@ -24,6 +24,7 @@
 #include "user_config.hpp"
 #include "menu_manager.hpp"
 #include "translation.hpp"
+#include "sdldrv.hpp"
 
 #include <string>
 
@@ -88,6 +89,8 @@ void PlayerControls::select()
     }
     m_edit_action   = static_cast<KartActions>(MENU_CHOICE);
     m_grab_input = true;
+    drv_hidePointer();
+
     widgetSet->set_label(m_grab_id, _("Press key"));
 }   // select
 
@@ -138,6 +141,7 @@ void PlayerControls::input(InputType type, int id0, int id1, int id2, int value)
         // ------------------------------
         else
         {
+            drv_showPointer();
             m_grab_input = false;
 
             // Do not accept pressing ESC as input.
diff --git a/src/gui/race_gui.cpp b/src/gui/race_gui.cpp
index 8032e7c34..0d021eb22 100644
--- a/src/gui/race_gui.cpp
+++ b/src/gui/race_gui.cpp
@@ -29,8 +29,9 @@
 #include "sdldrv.hpp"
 #include "translation.hpp"
 #include "font.hpp"
+#include "inputmap.hpp"
 
-RaceGUI::RaceGUI(): m_time_left(0.0)
+RaceGUI::RaceGUI(): m_input_map (new InputMap()), m_time_left(0.0)
 {
     if(user_config->m_fullscreen)
     {
@@ -39,7 +40,7 @@ RaceGUI::RaceGUI(): m_time_left(0.0)
 
     if(!user_config->m_profile)
     {
-        UpdateKeyboardMappings();
+        updateInputMappings();
     }   // if !user_config->m_profile
 
     // FIXME: translation problem
@@ -74,6 +75,8 @@ RaceGUI::RaceGUI(): m_time_left(0.0)
 //-----------------------------------------------------------------------------
 RaceGUI::~RaceGUI()
 {
+  delete m_input_map;
+
     if(user_config->m_fullscreen)
     {
         SDL_ShowCursor(SDL_ENABLE);
@@ -82,15 +85,9 @@ RaceGUI::~RaceGUI()
 }   // ~Racegui
 
 //-----------------------------------------------------------------------------
-void RaceGUI::UpdateKeyboardMappings()
+void RaceGUI::updateInputMappings()
 {
-    // Clear all entries.
-    for(int type = 0;type< (int) IT_LAST+1;type++)
-        for(int id0=0;id0<MAX_ID0;id0++)
-            for(int id1=0;id1<MAX_ID1;id1++)
-                for(int id2=0;id2<MAX_ID2;id2++)
-                    m_input_map[type][id0][id1][id2].kart = NULL;
-
+  m_input_map->clear();
 
     // Defines the mappings for player keys to kart and action
     // To avoid looping over all players to find out what
@@ -104,29 +101,19 @@ void RaceGUI::UpdateKeyboardMappings()
         PlayerKart* kart = world->getPlayerKart(i);
 
         for(int ka=(int)KC_FIRST; ka < (int)KC_LAST+1; ka++)
-            putEntry(kart, (KartActions) ka);
+            m_input_map->putEntry(kart, (KartActions) ka);
     }
 
 }   // UpdateKeyControl
 
-//-----------------------------------------------------------------------------
-void RaceGUI::putEntry(PlayerKart *kart, KartActions kc)
-{
-    Player *p = kart->getPlayer();
-    const Input *I  = p->getInput(kc);
-
-    m_input_map[I->type][I->id0][I->id1][I->id2].kart = kart;
-    m_input_map[I->type][I->id0][I->id1][I->id2].action = kc;
-}
-
 //-----------------------------------------------------------------------------
 bool RaceGUI::handleInput(InputType type, int id0, int id1, int id2, int value)
 {
-    PlayerKart *k = m_input_map[type][id0][id1][id2].kart;
+    InputMap::Entry *e = m_input_map->getEntry(type, id0, id1, id2);
 
-    if (k)
+    if (e)
     {
-        k->action(m_input_map[type][id0][id1][id2].action, value);
+        e->kart->action(e->action, value);
         return true;
     }
     else
diff --git a/src/gui/race_gui.hpp b/src/gui/race_gui.hpp
index d7f3d241c..996f7c556 100644
--- a/src/gui/race_gui.hpp
+++ b/src/gui/race_gui.hpp
@@ -31,25 +31,11 @@
 #include "player.hpp"
 #include "world.hpp"
 
-// TODO: Fix this.
-#define MAX_ID0 512
-#define MAX_ID1 16
-#define MAX_ID2 2
-
-typedef struct
-{
-    PlayerKart *kart;
-    KartActions action;
-}
-Entry;
-
+class InputMap;
 class RaceSetup;
 
 class RaceGUI: public BaseGUI
 {
-    // A mapping for the assigned keys (like fire, ...) to
-    // the kart which is using them
-    Entry m_input_map[IT_LAST+1][MAX_ID0][MAX_ID1][MAX_ID2];
 
     class TimedMessage
     {
@@ -86,6 +72,7 @@ public:
                     int red=255, int green=0, int blue=255);
 
 private:
+    InputMap *m_input_map;
     ulClock     m_fps_timer;
     int         m_fps_counter;
     char        m_fps_string[10];
@@ -108,8 +95,7 @@ private:
     void drawAllMessages       (Kart* player_kart,
                                 int   offset_x, int   offset_y,
                                 float ratio_x,  float ratio_y  );
-    void UpdateKeyboardMappings();
-    void putEntry(PlayerKart *kart, KartActions ka);
+    void updateInputMappings();
     bool handleInput(InputType type, int id0, int id1, int id2, int value);
     void inputKeyboard(int key, int pressed);
     void drawPlayerIcons       ();
diff --git a/src/inputmap.cpp b/src/inputmap.cpp
new file mode 100644
index 000000000..a08ef7e30
--- /dev/null
+++ b/src/inputmap.cpp
@@ -0,0 +1,74 @@
+//  $Id: inputmap.cpp 1259 2007-09-24 12:28:19Z thebohemian $
+//
+//  SuperTuxKart - a fun racing game with go-kart
+//  Copyright (C) 2007 Robert Schuster
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program 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 General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+#include <map>
+
+#include "player.hpp"
+#include "player_kart.hpp"
+#include "inputmap.hpp"
+
+using namespace std;
+
+void
+InputMap::putEntry(PlayerKart *kart, KartActions kc)
+{
+    Player *p = kart->getPlayer();
+    const Input *i  = p->getInput(kc);
+
+    Entry *e = new Entry();
+    e->kart = kart;
+    e->action = kc;
+
+    inputMap[key(i->type, i->id0, i->id1, i->id2)] = e;
+}
+
+InputMap::Entry *
+InputMap::getEntry(InputType it, int id0, int id1, int id2)
+{
+  return inputMap[key(it, id0, id1, id2)];
+}
+
+void
+InputMap::clear()
+{
+    for (map<Key, Entry *>::iterator i = inputMap.begin();
+         i != inputMap.end(); i++)
+    {
+      delete i->second;
+    }
+
+    inputMap.clear();
+}
+
+InputMap::Key
+InputMap::key(InputType it, int id0, int id1, int id2)
+{
+    /*
+     * A short reminder on the bit distribution and their usage:
+     * it gets 8 bits (InputType)
+     * id1 gets 16 bits (button, hat or axis number)
+     * id2 gets 8 bits (direction bit)
+     * id0 gets 32 bits (That is because id0 can be the keyboard key ids and
+     * those are unicode and unicode 4.0 is 32 bit)
+     *
+     * Assumption: int is (at least) 32 bit
+     */
+    return Key(it << 24 | id1 << 8 | id2, id0);
+}
+
diff --git a/src/inputmap.hpp b/src/inputmap.hpp
new file mode 100644
index 000000000..3e7f5e55e
--- /dev/null
+++ b/src/inputmap.hpp
@@ -0,0 +1,52 @@
+//  $Id: inputmap.hpp 1259 2007-09-24 12:28:19Z thebohemian $
+//
+//  SuperTuxKart - a fun racing game with go-kart
+//  Copyright (C) 2007 Robert Schuster
+//
+//  This program is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU General Public License
+//  as published by the Free Software Foundation; either version 2
+//  of the License, or (at your option) any later version.
+//
+//  This program 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 General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+#ifndef HEADER_INPUTMAP_H
+#define HEADER_INPUTMAP_H
+
+#include <map>
+#include "player.hpp"
+
+class Playerkart;
+
+class InputMap
+{
+  typedef std::pair<int, int> Key;
+
+  public:
+    typedef struct
+    {
+      PlayerKart *kart;
+      KartActions action;
+    } Entry;
+
+    void clear();
+
+    void putEntry(PlayerKart *, KartActions);
+
+    Entry *getEntry(InputType, int, int, int);
+
+  private:
+    Key key(InputType, int, int, int);
+
+    std::map<Key, Entry *> inputMap;
+
+};
+
+#endif
diff --git a/src/sdldrv.cpp b/src/sdldrv.cpp
index 267ad7e36..dc39ac701 100755
--- a/src/sdldrv.cpp
+++ b/src/sdldrv.cpp
@@ -39,9 +39,15 @@ SDL_Surface *mainSurface;
 long flags;
 SDL_Joystick **sticks;
 
+bool pointerVisible = true;
+
 #define DEADZONE_MOUSE 1
 #define DEADZONE_JOYSTICK 1000
 
+#define MULTIPLIER_MOUSE 750
+int mouseValX = 0;
+int mouseValY = 0;
+
 //-----------------------------------------------------------------------------
 void drv_init()
 {
@@ -67,6 +73,20 @@ void drv_init()
     ssgInit () ;
 }
 
+//-----------------------------------------------------------------------------
+void
+drv_showPointer()
+{
+  pointerVisible = true;
+  SDL_ShowCursor(SDL_ENABLE);
+}
+//-----------------------------------------------------------------------------
+void
+drv_hidePointer()
+{
+  pointerVisible = false;
+  SDL_ShowCursor(SDL_DISABLE);
+}
 //-----------------------------------------------------------------------------
 void drv_toggleFullscreen(int resetTextures)
 {
@@ -79,10 +99,10 @@ void drv_toggleFullscreen(int resetTextures)
         flags |= SDL_FULLSCREEN;
 
         if(menu_manager->isSomewhereOnStack(MENUID_RACE))
-            SDL_ShowCursor(SDL_DISABLE);
+          drv_showPointer();
     }
     else if(menu_manager->isSomewhereOnStack(MENUID_RACE))
-            SDL_ShowCursor(SDL_ENABLE);
+        drv_hidePointer();
 
     SDL_FreeSurface(mainSurface);
     mainSurface = SDL_SetVideoMode(user_config->m_width, user_config->m_height, 0, flags);
@@ -168,32 +188,28 @@ void drv_loop()
             break;
 
         case SDL_MOUSEMOTION:
-            input(IT_MOUSEMOTION, ev.motion.x, mainSurface->h - ev.motion.y, 0, 0);
-
-#ifdef ALT_MOUSE_HANDLING
-            // This probably needs better handling
-            if (ev.motion.xrel < -DEADZONE_MOUSE)
-                input(IT_MOUSEMOTION, 0, AD_NEGATIVE, 0, 1);
-            else if(ev.motion.xrel > DEADZONE_MOUSE)
-                input(IT_MOUSEMOTION, 0, AD_POSITIVE, 0, 1);
-            else
-            {
-                input(IT_MOUSEMOTION, 0, AD_NEGATIVE, 0, 0);
-                input(IT_MOUSEMOTION, 0, AD_POSITIVE, 0, 0);
-            }
-
-            if (ev.motion.yrel < -DEADZONE_MOUSE)
-                input(IT_MOUSEMOTION, 1, AD_NEGATIVE, 0, 1);
-            else if(ev.motion.yrel > DEADZONE_MOUSE)
-                input(IT_MOUSEMOTION, 1, AD_POSITIVE, 0, 1);
-            else
-            {
-                input(IT_MOUSEMOTION, 1, AD_NEGATIVE, 0, 0);
-                input(IT_MOUSEMOTION, 1, AD_POSITIVE, 0, 0);
-            }
-#endif
-            break;
+          if (pointerVisible)
+          {
+            BaseGUI* menu= menu_manager->getCurrentMenu();
+            if (menu != NULL)
+              menu->inputPointer(ev.motion.x, mainSurface->h - ev.motion.y);
 
+            // Reset parameters for relative mouse handling to make sure we are
+            // in a valid state when returning to relative mouse mode
+            mouseValX = mouseValY = 0;
+          }
+          else
+          {
+            mouseValX = std::max(-32768,
+                                 std::min(32768, mouseValX
+                                                 + ev.motion.xrel
+                                                 * MULTIPLIER_MOUSE));
+            mouseValY = std::max(-32768,
+                                 std::min(32768, mouseValY
+                                                 + ev.motion.yrel
+                                                 * MULTIPLIER_MOUSE));
+          }
+          break;
         case SDL_MOUSEBUTTONUP:
             input(IT_MOUSEBUTTON, ev.button.button, 0, 0, 0);
             break;
@@ -224,4 +240,16 @@ void drv_loop()
             break;
         }  // switch
     }   // while (SDL_PollEvent())
+
+    // Makes mouse behave like an analog axis.
+    if (mouseValX <= DEADZONE_MOUSE)
+      input(IT_MOUSEMOTION, 0, AD_NEGATIVE, 0, -mouseValX);
+    else if (mouseValX >= DEADZONE_MOUSE)
+      input(IT_MOUSEMOTION, 0, AD_POSITIVE, 0, mouseValX);
+
+    if (mouseValY <= DEADZONE_MOUSE)
+      input(IT_MOUSEMOTION, 1, AD_NEGATIVE, 0, -mouseValY);
+    else if (mouseValY >= DEADZONE_MOUSE)
+      input(IT_MOUSEMOTION, 1, AD_POSITIVE, 0, mouseValY);
+
 }
diff --git a/src/sdldrv.hpp b/src/sdldrv.hpp
index 81186e595..2c22eb978 100755
--- a/src/sdldrv.hpp
+++ b/src/sdldrv.hpp
@@ -20,9 +20,14 @@
 #ifndef HEADER_SDLDRV_H
 #define HEADER_SDLDRV_H
 
+enum MouseState { INITIAL, MOVED, RESET_NEEDED }; 
+
 void drv_init();
 void drv_deinit();
 
+void drv_showPointer();
+void drv_hidePointer();
+
 void drv_toggleFullscreen(int resetTextures=1);
 
 void drv_loop();