Index: code/trunk/src/core/InputHandler.cc
===================================================================
--- code/trunk/src/core/InputHandler.cc	(revision 1293)
+++ code/trunk/src/core/InputHandler.cc	(revision 1349)
@@ -34,12 +34,269 @@
 #include "InputHandler.h"
 #include "util/Convert.h"
+#include "util/SubString.h"
+#include "util/String.h"
 #include "Debug.h"
 #include "ConfigValueIncludes.h"
 #include "CoreIncludes.h"
 #include "CommandExecutor.h"
+#include "Executor.h"
 
 namespace orxonox
 {
   // ###############################
+  // ######      Button       ######
+  // ###############################
+
+  bool BufferedParamCommand::execute()
+  {
+    if (nValuesAdded_)
+    {
+      BufferedParamCommand& cmd = *this;
+      cmd.evaluation_.setEvaluatedParameter(cmd.paramIndex_, cmd.value_);
+      // reset
+      cmd.nValuesAdded_ = 0;
+      cmd.value_ = 0;
+      return CommandExecutor::execute(cmd.evaluation_);
+    }
+    else
+      return true;
+  }
+
+  bool SimpleCommand::execute(float abs, float rel)
+  {
+    return CommandExecutor::execute(evaluation_);
+  }
+
+  bool ParamCommand::execute(float abs, float rel)
+  {
+    BufferedParamCommand& paramCommand = *paramCommand_;
+    // command has an additional parameter
+    if (bRelative_ && (rel > 0 || rel < 0))
+    {
+      // we have to calculate a relative movement.
+      // paramModifier_ says how much one keystroke is
+      paramCommand.value_ += paramModifier_ * rel;
+    }
+    else if (abs > 0 || abs < 0)
+    {
+      // we have to calculate absolute position of the axis.
+      // Since there might be another axis that is affected, we have to wait and
+      // store the result in a temporary place
+      paramCommand.value_ = (paramCommand.value_ * paramCommand.nValuesAdded_ + paramModifier_ * abs)
+                            /++paramCommand.nValuesAdded_;
+    }
+    return true;
+  }
+
+  void Button::clear()
+  {
+    for (unsigned int j = 0; j < 3; j++)
+    {
+      if (nCommands_[j])
+      {
+        // delete all commands and the command pointer array
+        for (unsigned int i = 0; i < nCommands_[j]; i++)
+          delete commands_[j][i];
+        delete[] commands_[j];
+        commands_[j] = 0;
+        nCommands_[j] = 0;
+      }
+      else
+      {
+        commands_[j] = 0;
+      }
+    }
+  }
+
+  void Button::parse(std::vector<BufferedParamCommand*>& paramCommandBuffer)
+  {
+    if (isEmpty(bindingString_))
+    {
+      clear();
+      return;
+    }
+
+    // use std::vector for a temporary dynamic array
+    std::vector<BaseCommand*> commands[3];
+
+
+    // separate the commands
+    SubString commandStrings(bindingString_, "|", SubString::WhiteSpaces, false,
+        '\\', false, '"', false, '(', ')', false, '\0');
+
+    for (unsigned int iCommand = 0; iCommand < commandStrings.size(); iCommand++)
+    {
+      if (commandStrings[iCommand] != "")
+      {
+        SubString tokens(commandStrings[iCommand], " ", SubString::WhiteSpaces, false,
+            '\\', false, '"', false, '(', ')', false, '\0');
+        
+        unsigned int iToken = 0;
+
+        // for real axes, we can feed a ButtonThreshold argument as entire command
+        if (getLowercase(tokens[0]) == "buttonthreshold")
+        {
+          if (tokens.size() == 1)
+            continue;
+          // may fail, but doesn't matter
+          convertValue(&buttonThreshold_, tokens[1]);
+          continue;
+        }
+
+        // first argument can be OnPress, OnHold OnRelease or nothing
+        KeybindMode::Enum mode = KeybindMode::None;
+        if (getLowercase(tokens[iToken]) == "onpress")
+          mode = KeybindMode::OnPress,   iToken++;
+        if (getLowercase(tokens[iToken]) == "onrelease")
+          mode = KeybindMode::OnRelease, iToken++;
+        if (getLowercase(tokens[iToken]) == "onhold")
+          mode = KeybindMode::OnHold,    iToken++;
+
+        if (iToken == tokens.size())
+          continue;
+
+        // second argument can be the amplitude for the case it as an axis command
+        // default amplitude is 1.0f
+        float paramModifier = 1.0f;
+        if (getLowercase(tokens[iToken]) == "axisamp")
+        {
+          iToken++;
+          if (iToken == tokens.size() || !convertValue(&paramModifier, tokens[iToken]))
+          {
+            COUT(2) << "Error while parsing key binding " << name_
+                << ". Numeric expression expected afer 'AxisAmp', switching to default value" << std::endl;
+            if (iToken == tokens.size())
+              continue;
+          }
+          iToken++;
+        }
+
+        // no more arguments expected except for the actual command
+        if (iToken == tokens.size())
+          continue;
+
+        std::string commandStr;
+        while (iToken != tokens.size())
+          commandStr += tokens[iToken++] + " ";
+
+        // evaluate the command
+        CommandEvaluation eval = CommandExecutor::evaluate(commandStr);
+        if (!eval.isValid())
+          continue;
+
+        // check for param command
+        int paramIndex = eval.getEvaluatedExecutor()->getAxisParamIndex();
+        // TODO: check in Executor for correct paramIndex
+        if (paramIndex >= 0)
+        {
+          // parameter supported command
+          ParamCommand* cmd = new ParamCommand();
+          cmd->paramModifier_ = paramModifier;
+          cmd->bRelative_ = eval.getEvaluatedExecutor()->getIsAxisRelative();
+
+          // add command to the buffer if not yet existing
+          for (unsigned int iParamCmd = 0; iParamCmd < paramCommandBuffer.size(); iParamCmd++)
+          {
+            if (getLowercase(paramCommandBuffer[iParamCmd]->evaluation_.getCommandString())
+                == getLowercase(commandStr))
+            {
+              // already in list
+              cmd->paramCommand_ = paramCommandBuffer[iParamCmd];
+              break;
+            }
+          }
+          if (cmd->paramCommand_ == 0)
+          {
+            cmd->paramCommand_ = new BufferedParamCommand();
+            paramCommandBuffer.push_back(cmd->paramCommand_);
+            cmd->paramCommand_->evaluation_ = eval;
+            cmd->paramCommand_->paramIndex_ = paramIndex;
+          }
+
+
+          // we don't know whether this is an actual axis or just a button
+          if (mode == KeybindMode::None)
+          {
+            if (!addParamCommand(cmd))
+            {
+              mode = eval.getEvaluatedExecutor()->getKeybindMode();
+              commands[mode].push_back(cmd);
+            }
+          }
+        }
+        else
+        {
+          SimpleCommand* cmd = new SimpleCommand();
+          cmd->evaluation_ = eval;
+
+          //TODO: check CommandEvaluation for correct KeybindMode
+          if (mode == KeybindMode::None)
+            mode = eval.getEvaluatedExecutor()->getKeybindMode();
+
+          commands[mode].push_back(cmd);
+        }
+      }
+    }
+
+    for (unsigned int j = 0; j < 3; j++)
+    {
+      nCommands_[j] = commands[j].size();
+      if (nCommands_[j])
+      {
+        commands_[j] = new BaseCommand*[nCommands_[j]];
+        for (unsigned int i = 0; i < commands[j].size(); i++)
+          commands_[j][i] = commands[j][i];
+      }
+      else
+        commands_[j] = 0;
+    }
+  }
+
+  bool Button::execute(KeybindMode::Enum mode, float abs, float rel)
+  {
+    // execute all the parsed commands in the string
+    for (unsigned int iCommand = 0; iCommand < nCommands_[mode]; iCommand++)
+      commands_[mode][iCommand]->execute(abs, rel);
+    return true;
+  }
+
+  void HalfAxis::clear()
+  {
+    Button::clear();
+    if (nParamCommands_)
+    {
+      // delete all commands and the command pointer array
+      for (unsigned int i = 0; i < nParamCommands_; i++)
+        delete paramCommands_[i];
+      delete[] paramCommands_;
+    }
+    else
+    {
+      nParamCommands_ = 0; nParamCommands_ = 0;
+    }
+  }
+  
+  bool HalfAxis::addParamCommand(ParamCommand* command)
+  {
+    ParamCommand** cmds = paramCommands_;
+    paramCommands_ = new ParamCommand*[++nParamCommands_];
+    unsigned int i;
+    for (i = 0; i < nParamCommands_ - 1; i++)
+      paramCommands_[i] = cmds[i];
+    paramCommands_[i] = command;
+    delete[] cmds;
+    return true;
+  }
+
+  bool HalfAxis::execute()
+  {
+    bool success = true;
+    for (unsigned int i = 0; i < nParamCommands_; i++)
+      success = success && paramCommands_[i]->execute(absVal_, relVal_);
+    return success;
+  }
+
+
+  // ###############################
   // ######     KeyBinder     ######
   // ###############################
@@ -48,193 +305,144 @@
     @brief Constructor that does as little as necessary.
   */
-  KeyBinder::KeyBinder()
+  KeyBinder::KeyBinder() : deriveTime_(0.0f)
   {
     RegisterObject(KeyBinder);
-    clearBindings();
-
+
+    // keys
     std::string keyNames[] = {
-    "UNASSIGNED",
-    "ESCAPE",
-    "1",
-    "2",
-    "3",
-    "4",
-    "5",
-    "6",
-    "7",
-    "8",
-    "9",
-    "0",
-    "MINUS",
-    "EQUALS",
-    "BACK",
-    "TAB",
-    "Q",
-    "W",
-    "E",
-    "R",
-    "T",
-    "Y",
-    "U",
-    "I",
-    "O",
-    "P",
-    "LBRACKET",
-    "RBRACKET",
-    "RETURN",
-    "LCONTROL",
-    "A",
-    "S",
-    "D",
-    "F",
-    "G",
-    "H",
-    "J",
-    "K",
-    "L",
-    "SEMICOLON",
-    "APOSTROPHE",
-    "GRAVE",
-    "LSHIFT",
-    "BACKSLASH",
-    "Z",
-    "X",
-    "C",
-    "V",
-    "B",
-    "N",
-    "M",
-    "COMMA",
-    "PERIOD",
-    "SLASH",
-    "RSHIFT",
-    "MULTIPLY",
-    "LMENU",
-    "SPACE",
-    "CAPITAL",
-    "F1",
-    "F2",
-    "F3",
-    "F4",
-    "F5",
-    "F6",
-    "F7",
-    "F8",
-    "F9",
-    "F10",
-    "NUMLOCK",
-    "SCROLL",
-    "NUMPAD7",
-    "NUMPAD8",
-    "NUMPAD9",
-    "SUBTRACT",
-    "NUMPAD4",
-    "NUMPAD5",
-    "NUMPAD6",
-    "ADD",
-    "NUMPAD1",
-    "NUMPAD2",
-    "NUMPAD3",
-    "NUMPAD0",
-    "DECIMAL",
-    "","",
-    "OEM_102",
-    "F11",
-    "F12",
-    "","","","","","","","","","","",
-    "F13",
-    "F14",
-    "F15",
-    "","","","","","","","","","",
-    "KANA",
-    "","",
-    "ABNT_C1",
-    "","","","","",
-    "CONVERT",
-    "",
-    "NOCONVERT",
-    "",
-    "YEN",
-    "ABNT_C2",
-    "","","","","","","","","","","","","","",
-    "NUMPADEQUALS",
-    "","",
-    "PREVTRACK",
-    "AT",
-    "COLON",
-    "UNDERLINE",
-    "KANJI",
-    "STOP",
-    "AX",
-    "UNLABELED",
-    "NEXTTRACK",
-    "","",
-    "NUMPADENTER",
-    "RCONTROL",
-    "","",
-    "MUTE",
-    "CALCULATOR",
-    "PLAYPAUSE",
-    "",
-    "MEDIASTOP",
-    "","","","","","","","","",
-    "VOLUMEDOWN",
-    "",
-    "VOLUMEUP",
-    "",
-    "WEBHOME",
-    "NUMPADCOMMA",
-    "",
-    "DIVIDE",
-    "",
-    "SYSRQ",
-    "RMENU",
-    "","","","","","","","","","","","",
-    "PAUSE",
-    "",
-    "HOME",
-    "UP",
-    "PGUP",
-    "",
-    "LEFT",
-    "",
-    "RIGHT",
-    "",
-    "END",
-    "DOWN",
-    "PGDOWN",
-    "INSERT",
-    "DELETE",
-    "","","","","","","",
-    "LWIN",
-    "RWIN",
-    "APPS",
-    "POWER",
-    "SLEEP",
-    "","","",
-    "WAKE",
-    "",
-    "WEBSEARCH",
-    "WEBFAVORITES",
-    "WEBREFRESH",
-    "WEBSTOP",
-    "WEBFORWARD",
-    "WEBBACK",
-    "MYCOMPUTER",
-    "MAIL",
-    "MEDIASELECT"
+      "UNASSIGNED",
+      "ESCAPE",
+      "1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
+      "MINUS", "EQUALS", "BACK", "TAB",
+      "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P",
+      "LBRACKET", "RBRACKET",
+      "RETURN", "LCONTROL",
+      "A", "S", "D", "F", "G", "H", "J", "K", "L",
+      "SEMICOLON", "APOSTROPHE", "GRAVE",
+      "LSHIFT", "BACKSLASH",
+      "Z", "X", "C", "V", "B", "N", "M",
+      "COMMA", "PERIOD", "SLASH",
+      "RSHIFT",
+      "MULTIPLY",
+      "LMENU",
+      "SPACE",
+      "CAPITAL",
+      "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10",
+      "NUMLOCK", "SCROLL",
+      "NUMPAD7", "NUMPAD8", "NUMPAD9",
+      "SUBTRACT",
+      "NUMPAD4", "NUMPAD5", "NUMPAD6",
+      "ADD",
+      "NUMPAD1", "NUMPAD2", "NUMPAD3", "NUMPAD0",
+      "DECIMAL",
+      "","",
+      "OEM_102",
+      "F11", "F12",
+      "","","","","","","","","","","",
+      "F13", "F14", "F15",
+      "","","","","","","","","","",
+      "KANA",
+      "","",
+      "ABNT_C1",
+      "","","","","",
+      "CONVERT",
+      "",
+      "NOCONVERT",
+      "",
+      "YEN",
+      "ABNT_C2",
+      "","","","","","","","","","","","","","",
+      "NUMPADEQUALS",
+      "","",
+      "PREVTRACK",
+      "AT",
+      "COLON", "UNDERLINE",
+      "KANJI",
+      "STOP",
+      "AX",
+      "UNLABELED",
+      "NEXTTRACK",
+      "","",
+      "NUMPADENTER",
+      "RCONTROL",
+      "","",
+      "MUTE",
+      "CALCULATOR",
+      "PLAYPAUSE",
+      "",
+      "MEDIASTOP",
+      "","","","","","","","","",
+      "VOLUMEDOWN",
+      "",
+      "VOLUMEUP",
+      "",
+      "WEBHOME",
+      "NUMPADCOMMA",
+      "",
+      "DIVIDE",
+      "",
+      "SYSRQ",
+      "RMENU",
+      "","","","","","","","","","","","",
+      "PAUSE",
+      "",
+      "HOME",
+      "UP",
+      "PGUP",
+      "",
+      "LEFT",
+      "",
+      "RIGHT",
+      "",
+      "END", "DOWN", "PGDOWN", "INSERT", "DELETE",
+      "","","","","","","",
+      "LWIN", "RWIN", "APPS",
+      "POWER", "SLEEP",
+      "","","",
+      "WAKE",
+      "",
+      "WEBSEARCH", "WEBFAVORITES", "WEBREFRESH", "WEBSTOP", "WEBFORWARD", "WEBBACK",
+      "MYCOMPUTER", "MAIL", "MEDIASELECT"
     };
-    for (int i = 0; i < numberOfKeys_s; i++)
-      keyNames_[i] = keyNames[i];
-
+    for (unsigned int i = 0; i < nKeys_s; i++)
+      keys_[i].name_ = "Key" + keyNames[i];
+
+    // mouse buttons
     std::string mouseButtonNames[] = {
       "MouseLeft", "MouseRight", "MouseMiddle",
       "MouseButton3", "MouseButton4", "MouseButton5",
-      "MouseButton6", "MouseButton7" };
-    for (int i = 0; i < numberOfMouseButtons_s; i++)
-      mouseButtonNames_[i] = mouseButtonNames[i];
-
-    for (int i = 0; i < numberOfJoyStickButtons_s; i++)
-      joyStickButtonNames_[i] = "JoyStick" + getConvertedValue<int, std::string>(i);
+      "MouseButton6", "MouseButton7",
+      "MouseWheel1Up", "MouseWheel1Down",
+      "MouseWheel2Up", "MouseWheel2Down" };
+    for (unsigned int i = 0; i < nMouseButtons_s; i++)
+      mouseButtons_[i].name_ = mouseButtonNames[i];
+
+    // joy stick buttons
+    for (unsigned int i = 0; i < 32; i++)
+      joyStickButtons_[i].name_ = "JoyButton" + getConvertedValue<int, std::string>(i);
+    for (unsigned int i = 32; i < nJoyStickButtons_s; i += 4)
+    {
+		  joyStickButtons_[i + 0].name_ = "JoyPOV" + getConvertedValue<int, std::string>((i - 32)/4 + 1) + "North";
+		  joyStickButtons_[i + 1].name_ = "JoyPOV" + getConvertedValue<int, std::string>((i - 32)/4 + 1) + "South";
+		  joyStickButtons_[i + 2].name_ = "JoyPOV" + getConvertedValue<int, std::string>((i - 32)/4 + 1) + "East";
+		  joyStickButtons_[i + 3].name_ = "JoyPOV" + getConvertedValue<int, std::string>((i - 32)/4 + 1) + "West";
+    }
+
+    // half axes
+    std::string rawNames[nHalfAxes_s/2];
+    rawNames[0] = "MouseX";
+    rawNames[1] = "MouseY";
+    rawNames[2] = "Empty1";
+    rawNames[3] = "Empty2";
+    for (unsigned int i = 4; i < nHalfAxes_s/2; i++)
+      rawNames[i] = "JoyAxis" + getConvertedValue<int, std::string>(i - 3);
+    for (unsigned int i = 0; i < nHalfAxes_s/2; i++)
+    {
+      halfAxes_[i * 2 + 0].name_ = rawNames[i] + "Pos";
+      halfAxes_[i * 2 + 1].name_ = rawNames[i] + "Neg";
+    }
+
+    for (unsigned int i = 0; i < this->nHalfAxes_s; i++)
+      halfAxes_[i].buttonThreshold_ = buttonThreshold_;
   }
 
@@ -244,4 +452,21 @@
   KeyBinder::~KeyBinder()
   {
+    // almost no destructors required because most of the arrays are static.
+    clearBindings(); // does some destruction work
+  }
+
+  /**
+    @brief Loads the key and button bindings.
+    @return True if loading succeeded.
+  */
+  void KeyBinder::loadBindings()
+  {
+    COUT(3) << "KeyBinder: Loading key bindings..." << std::endl;
+
+    ConfigFileManager::getSingleton()->setFile(CFT_Keybindings, "keybindings.ini");
+    clearBindings();
+    setConfigValues();
+
+    COUT(3) << "KeyBinder: Loading key bindings done." << std::endl;
   }
 
@@ -251,80 +476,47 @@
   void KeyBinder::setConfigValues()
   {
-    ConfigValueContainer* cont;
-    std::string modes[] = {"P_", "R_", "H_"};
+    SetConfigValue(analogThreshold_, 0.01f)  .description("Threshold for analog axes until which the state is 0.");
+    SetConfigValue(bDeriveMouseInput_, false).description("Whether or not to derive moues movement for the absolute value.");
+    SetConfigValue(derivePeriod_, 0.1f)      .description("Accuracy of the mouse input deriver. The higher the more precise, but laggier.");
+    SetConfigValue(mouseSensitivity_, 1.0f)  .description("Mouse sensitivity.");
+
+    float oldThresh = buttonThreshold_;
+    SetConfigValue(buttonThreshold_, 0.80f).description("Threshold for analog axes until which the button is not pressed.");
+    if (oldThresh != buttonThreshold_)
+      for (unsigned int i = 0; i < nHalfAxes_s; i++)
+        if (halfAxes_[i].buttonThreshold_ == oldThresh)
+          halfAxes_[i].buttonThreshold_ = buttonThreshold_;
 
     // keys
-    for (int i = 0; i < numberOfKeys_s; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        cont = getIdentifier()->getConfigValueContainer(modes[j] + keyNames_[i]);
-        if (!cont)
-        {
-          cont = new ConfigValueContainer(CFT_Keybindings, getIdentifier(), modes[j] + keyNames_[i], "");
-          getIdentifier()->addConfigValueContainer(modes[j] + keyNames_[i], cont);
-        }
-        switch (j)
-        {
-          case 0:
-            cont->getValue(&bindingsKeyPress_[i].commandStr);
-            break;
-          case 1:
-            cont->getValue(&bindingsKeyRelease_[i].commandStr);
-            break;
-          case 2:
-            cont->getValue(&bindingsKeyHold_[i].commandStr);
-        }
-      }
-    }
-
+    for (unsigned int i = 0; i < nKeys_s; i++)
+      readTrigger(keys_[i]);
     // mouse buttons
-    for (int i = 0; i < numberOfMouseButtons_s; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        cont = getIdentifier()->getConfigValueContainer(modes[j] + mouseButtonNames_[i]);
-        if (!cont)
-        {
-          cont = new ConfigValueContainer(CFT_Keybindings, getIdentifier(), modes[j] + mouseButtonNames_[i], "");
-          getIdentifier()->addConfigValueContainer(modes[j] + mouseButtonNames_[i], cont);
-        }
-        switch (j)
-        {
-          case 0:
-            cont->getValue(&bindingsMouseButtonPress_[i].commandStr);
-            break;
-          case 1:
-            cont->getValue(&bindingsMouseButtonRelease_[i].commandStr);
-            break;
-          case 2:
-            cont->getValue(&bindingsMouseButtonHold_[i].commandStr);
-        }
-      }
-    }
-
+    for (unsigned int i = 0; i < nMouseButtons_s; i++)
+      readTrigger(mouseButtons_[i]);
     // joy stick buttons
-    for (int i = 0; i < numberOfJoyStickButtons_s; i++)
-    {
-      for (int j = 0; j < 3; j++)
-      {
-        cont = getIdentifier()->getConfigValueContainer(modes[j] + joyStickButtonNames_[i]);
-        if (!cont)
-        {
-          cont = new ConfigValueContainer(CFT_Keybindings, getIdentifier(), modes[j] + joyStickButtonNames_[i], "");
-          getIdentifier()->addConfigValueContainer(modes[j] + joyStickButtonNames_[i], cont);
-        }
-        switch (j)
-        {
-          case 0:
-            cont->getValue(&bindingsJoyStickButtonPress_[i].commandStr);
-            break;
-          case 1:
-            cont->getValue(&bindingsJoyStickButtonRelease_[i].commandStr);
-            break;
-          case 2:
-            cont->getValue(&bindingsJoyStickButtonHold_[i].commandStr);
-        }
-      }
+    for (unsigned int i = 0; i < nJoyStickButtons_s; i++)
+      readTrigger(joyStickButtons_[i]);
+    // half axes
+    for (unsigned int i = 0; i < nHalfAxes_s; i++)
+      readTrigger(halfAxes_[i]);
+  }
+
+  void KeyBinder::readTrigger(Button& button)
+  {
+    // config value stuff
+    ConfigValueContainer* cont = getIdentifier()->getConfigValueContainer(button.name_);
+    if (!cont)
+    {
+      cont = new ConfigValueContainer(CFT_Keybindings, getIdentifier(), button.name_, "");
+      getIdentifier()->addConfigValueContainer(button.name_, cont);
+    }
+    std::string old = button.bindingString_;
+    cont->getValue(&button.bindingString_);
+
+    // keybinder stuff
+    if (old != button.bindingString_)
+    {
+      // binding has changed
+      button.parse(paramCommandBuffer_);
     }
   }
@@ -333,105 +525,121 @@
     @brief Overwrites all bindings with ""
   */
-  void KeyBinder::clearBindings()
-  {
-    for (int i = 0; i < numberOfKeys_s; i++)
-    {
-      bindingsKeyPress_  [i].commandStr = "";
-      bindingsKeyRelease_[i].commandStr = "";
-      bindingsKeyHold_   [i].commandStr = "";
-    }
-    for (int i = 0; i < numberOfMouseButtons_s; i++)
-    {
-      bindingsMouseButtonPress_  [i].commandStr = "";
-      bindingsMouseButtonRelease_[i].commandStr = "";
-      bindingsMouseButtonHold_   [i].commandStr = "";
-    }
-    for (int i = 0; i < numberOfJoyStickButtons_s; i++)
-    {
-      bindingsJoyStickButtonPress_  [i].commandStr = "";
-      bindingsJoyStickButtonRelease_[i].commandStr = "";
-      bindingsJoyStickButtonHold_   [i].commandStr = "";
-    }
-  }
-
-  /**
-    @brief Loads the key and button bindings.
-    @return True if loading succeeded.
-  */
-  bool KeyBinder::loadBindings()
-  {
-    COUT(ORX_DEBUG) << "KeyBinder: Loading key bindings..." << std::endl;
-
-    ConfigFileManager::getSingleton()->setFile(CFT_Keybindings, "keybindings.ini");
-    setConfigValues();
-
-    // evaluate the key bindings
-    // TODO: what if binding is invalid?
-    for (int i = 0; i < numberOfKeys_s; i++)
-    {
-      if (bindingsKeyPress_[i].commandStr != "")
+  void KeyBinder::clearBindings(bool bInit)
+  {
+    for (unsigned int i = 0; i < nKeys_s; i++)
+      keys_[i].clear();
+
+    for (unsigned int i = 0; i < nMouseButtons_s; i++)
+      mouseButtons_[i].clear();
+
+    for (unsigned int i = 0; i < nJoyStickButtons_s; i++)
+      joyStickButtons_[i].clear();
+
+    for (unsigned int i = 0; i < nHalfAxes_s; i++)
+      halfAxes_[i].clear();
+
+    for (unsigned int i = 0; i < paramCommandBuffer_.size(); i++)
+      delete paramCommandBuffer_[i];
+    paramCommandBuffer_.clear();
+  }
+
+  void KeyBinder::tick(float dt)
+  {
+    // we have to process all the analog input since there is e.g. no 'mouseDoesntMove' event.
+    for (unsigned int i = 0; i < nHalfAxes_s; i++)
+    {
+      if (halfAxes_[i].hasChanged_)
       {
-        bindingsKeyPress_[i].evaluation = CommandExecutor::evaluate(bindingsKeyPress_[i].commandStr);
-        bindingsKeyPress_[i].commandStr = bindingsKeyPress_[i].evaluation.getCommandString();
+        if (!halfAxes_[i].wasDown_ && halfAxes_[i].absVal_ > halfAxes_[i].buttonThreshold_)
+        {
+          halfAxes_[i].wasDown_ = true;
+          if (halfAxes_[i].nCommands_[KeybindMode::OnPress])
+            halfAxes_[i].execute(KeybindMode::OnPress);
+        }
+        else if (halfAxes_[i].wasDown_ && halfAxes_[i].absVal_ < halfAxes_[i].buttonThreshold_)
+        {
+          halfAxes_[i].wasDown_ = false;
+          if (halfAxes_[i].nCommands_[KeybindMode::OnRelease])
+            halfAxes_[i].execute(KeybindMode::OnRelease);
+        }
+        if (halfAxes_[i].wasDown_)
+        {
+          if (halfAxes_[i].nCommands_[KeybindMode::OnHold])
+            halfAxes_[i].execute(KeybindMode::OnHold);
+        }
+        halfAxes_[i].hasChanged_ = false;
       }
-    }
-
-    COUT(ORX_DEBUG) << "KeyBinder: Loading key bindings done." << std::endl;
-    return true;
-  }
-
-  bool KeyBinder::executeSimpleBinding(KeyBinding& binding)
-  {
-    if (binding.commandStr != "")
-    {
-      if (binding.commandStr != binding.evaluation.getCommandString())
+
+      // these are the actually useful axis bindings for analog input AND output
+      if (halfAxes_[i].relVal_ > analogThreshold_ || halfAxes_[i].absVal_ > analogThreshold_)
       {
-        // key binding has changed, reevaluate the command string.
-        binding.evaluation = CommandExecutor::evaluate(binding.commandStr);
-        binding.commandStr = binding.evaluation.getCommandString();
+        halfAxes_[i].execute();
       }
-      COUT(ORX_DEBUG) << "Keybinding: Executing command: " << binding.commandStr << std::endl;
-      CommandExecutor::execute(binding.commandStr);
-    }
-
-    return true;
-  }
-
-
-  /**
-    @brief Event handler for the keyPressed Event.
-    @param e Event information
-  */
-  bool KeyBinder::keyPressed(const KeyEvent& evt)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsKeyPress_[int(evt.key)]);
-
-    return true;
-  }
-
-  /**
-    @brief Event handler for the keyReleased Event.
-    @param e Event information
-  */
-  bool KeyBinder::keyReleased(const KeyEvent& evt)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsKeyRelease_[int(evt.key)]);
-
-    return true;
-  }
-
-  /**
-    @brief Event handler for the keyHeld Event.
-    @param e Mouse state information
-  */
-  bool KeyBinder::keyHeld(const KeyEvent& evt)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsKeyHold_[int(evt.key)]);
-
-    return true;
-  }
+    }
+
+    if (bDeriveMouseInput_)
+    {
+      if (deriveTime_ > derivePeriod_)
+      {
+        deriveTime_ = 0.0f;
+        //CCOUT(3) << "mouse abs: ";
+        for (int i = 0; i < 2; i++)
+        {
+          if (mouseRelative_[i] > 0)
+          {
+            halfAxes_[2*i + 0].absVal_ = mouseRelative_[i] * derivePeriod_ / 500 * mouseSensitivity_;
+            halfAxes_[2*i + 1].absVal_ = 0.0f;
+          }
+          else if (mouseRelative_[0] < 0)
+          {
+            halfAxes_[2*i + 0].absVal_ = 0.0f;
+            halfAxes_[2*i + 1].absVal_ = -mouseRelative_[i] * derivePeriod_ / 500 * mouseSensitivity_;
+          }
+          //COUT(3) << mouseRelative_[i] << " | ";
+          mouseRelative_[i] = 0;
+        }
+        //COUT(3) << std::endl;
+      }
+      else
+        deriveTime_ += dt;
+    }
+
+    // execute all buffered bindings (addional parameter)
+    for (unsigned int i = 0; i < paramCommandBuffer_.size(); i++)
+      paramCommandBuffer_[i]->execute();
+
+    // always reset the relative movement of the mouse
+    for (unsigned int i = 0; i < 8; i++)
+      halfAxes_[i].relVal_ = 0.0f;
+  }
+
+  void KeyBinder::keyPressed (const KeyEvent& evt)
+  { keys_[evt.key].execute(KeybindMode::OnPress); }
+
+  void KeyBinder::keyReleased(const KeyEvent& evt)
+  { keys_[evt.key].execute(KeybindMode::OnRelease); }
+
+  void KeyBinder::keyHeld    (const KeyEvent& evt)
+  { keys_[evt.key].execute(KeybindMode::OnHold); }
+
+
+  void KeyBinder::mouseButtonPressed (MouseButton::Enum id)
+  { mouseButtons_[id].execute(KeybindMode::OnPress); }
+
+  void KeyBinder::mouseButtonReleased(MouseButton::Enum id)
+  { mouseButtons_[id].execute(KeybindMode::OnRelease); }
+
+  void KeyBinder::mouseButtonHeld    (MouseButton::Enum id)
+  { mouseButtons_[id].execute(KeybindMode::OnHold); }
+
+
+  void KeyBinder::joyStickButtonPressed (int joyStickID, int button)
+  { joyStickButtons_[button].execute(KeybindMode::OnPress); }
+
+  void KeyBinder::joyStickButtonReleased(int joyStickID, int button)
+  { joyStickButtons_[button].execute(KeybindMode::OnRelease); }
+
+  void KeyBinder::joyStickButtonHeld    (int joyStickID, int button)
+  { joyStickButtons_[button].execute(KeybindMode::OnHold); }
 
   /**
@@ -439,21 +647,58 @@
     @param e Mouse state information
   */
-  bool KeyBinder::mouseMoved(const MouseState &evt)
-  {
-    /*if (bindingMouseMoved_.commandStr != "")
-    {
-      if (bindingMouseMoved_.commandStr != bindingMouseMoved_.evaluation.getCommandString())
+  void KeyBinder::mouseMoved(IntVector2 abs_, IntVector2 rel_, IntVector2 clippingSize)
+  {
+    if (!bDeriveMouseInput_)
+    {
+      // y axis of mouse input is inverted
+      int rel[] = { rel_.x, -rel_.y };
+
+      //COUT(3) << rel[0] << " | " << rel[1] << std::endl;
+
+      for (int i = 0; i < 2; i++)
       {
-        // key binding has changed, reevaluate the command string.
-        bindingMouseMoved_.evaluation = CommandExecutor::evaluate(bindingMouseMoved_.commandStr);
-        bindingMouseMoved_.commandStr = bindingMouseMoved_.evaluation.getCommandString();
+        if (rel[i])
+        {
+          // absolute
+          if (mousePosition_[i] >= 0)
+          {
+            mousePosition_[i] += rel[i];
+            halfAxes_[0 + 2*i].hasChanged_ = true;
+            if (mousePosition_[i] < 0)
+            {
+              halfAxes_[1 + 2*i].hasChanged_ = true;
+              halfAxes_[1 + 2*i].absVal_ = -((float)mousePosition_[i])/1024 * mouseSensitivity_;
+              halfAxes_[0 + 2*i].absVal_ =  0.0f;
+            }
+            else
+              halfAxes_[1 + 2*i].absVal_ =  ((float)mousePosition_[i])/1024 * mouseSensitivity_;
+          }
+          else
+          {
+            mousePosition_[i] += rel[i];
+            halfAxes_[1 + 2*i].hasChanged_ = true;
+            if (mousePosition_[i] > 0)
+            {
+              halfAxes_[0 + 2*i].hasChanged_ = true;
+              halfAxes_[0 + 2*i].absVal_ =  ((float)mousePosition_[i])/1024 * mouseSensitivity_;
+              halfAxes_[1 + 2*i].absVal_ =  0.0f;
+            }
+            else
+              halfAxes_[1 + 2*i].absVal_ = -((float)mousePosition_[i])/1024 * mouseSensitivity_;
+          }
+
+          // relative
+          if (rel[i] > 0)
+            halfAxes_[0 + 2*i].relVal_ =  ((float)rel[i])/1024 * mouseSensitivity_;
+          else
+            halfAxes_[1 + 2*i].relVal_ = -((float)rel[i])/1024 * mouseSensitivity_;
+        }
       }
-      COUT(3) << "Executing command: " << bindingMouseMoved_.commandStr << std::endl;
-
-      bindingMouseMoved_.evaluation.setEvaluatedParameter(
-      CommandExecutor::execute(bindingMouseMoved_.commandStr);
-    }*/
-
-    return true;
+    }
+    else
+    {
+      mouseRelative_[0] += rel_.x;
+      mouseRelative_[1] -= rel_.y;
+    }
   }
 
@@ -462,92 +707,33 @@
     @param e Mouse state information
   */
-  bool KeyBinder::mouseScrolled(const MouseState &evt)
-  {
-    return true;
-  }
-
-  /**
-    @brief Event handler for the mousePressed Event.
-    @param e Event information
-    @param id The ID of the mouse button
-  */
-  bool KeyBinder::mouseButtonPressed(const MouseState& state, MouseButton::Enum id)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsMouseButtonPress_[int(id)]);
-
-    return true;
-  }
-
-  /**
-    @brief Event handler for the mouseReleased Event.
-    @param e Event information
-    @param id The ID of the mouse button
-  */
-  bool KeyBinder::mouseButtonReleased(const MouseState& state, MouseButton::Enum id)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsMouseButtonRelease_[int(id)]);
-
-    return true;
-  }
-
-  /**
-    @brief Event handler for the mouseHeld Event.
-    @param e Event information
-    @param id The ID of the mouse button
-  */
-  bool KeyBinder::mouseButtonHeld(const MouseState& state, MouseButton::Enum id)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsMouseButtonHold_[int(id)]);
-
-    return true;
-  }
-
-  bool KeyBinder::joyStickButtonPressed(const JoyStickState& state, int button)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsJoyStickButtonPress_[button]);
-
-    return true;
-  }
-
-  bool KeyBinder::joyStickButtonReleased(const JoyStickState& state, int button)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsJoyStickButtonRelease_[button]);
-
-    return true;
-  }
-
-  bool KeyBinder::joyStickButtonHeld(const JoyStickState& state, int button)
-  {
-    // find the appropriate key binding
-    executeSimpleBinding(bindingsJoyStickButtonHold_[button]);
-
-    return true;
-  }
-
-  bool KeyBinder::joyStickAxisMoved(const JoyStickState& state, int axis)
-  {
-    return true;
-  }
-
-  bool KeyBinder::joyStickSliderMoved(const JoyStickState& state, int index)
-  {
-    return true;
-  }
-
-  bool KeyBinder::joyStickPovMoved(const JoyStickState& state, int index)
-  {
-    return true;
-  }
-
-  bool KeyBinder::joyStickVector3Moved(const JoyStickState& state, int index)
-  {
-    return true;
-  }
-
+  void KeyBinder::mouseScrolled(int abs, int rel)
+  {
+    //COUT(3) << mouseButtons_[8].name_ << "   " << abs << " | " << rel << std::endl;
+
+    if (rel > 0)
+      for (int i = 0; i < rel/120; i++)
+        mouseButtons_[8].execute(KeybindMode::OnPress, ((float)abs)/120.0f);
+    else
+      for (int i = 0; i < -rel/120; i++)
+        mouseButtons_[9].execute(KeybindMode::OnPress, ((float)abs)/120.0f);
+  }
+
+  void KeyBinder::joyStickAxisMoved(int joyStickID, int axis, int value)
+  {
+    // TODO: check whether 16 bit integer as general axis value is a good idea (works under windows)
+    CCOUT(3) << halfAxes_[8 + axis].name_ << std::endl;
+    if (value >= 0)
+    {
+      halfAxes_[8 + axis].absVal_ = ((float)value)/0x8000;
+      halfAxes_[8 + axis].relVal_ = ((float)value)/0x8000;
+      halfAxes_[8 + axis].hasChanged_ = true;
+    }
+    else
+    {
+      halfAxes_[8 + axis + 1].absVal_ = -((float)value)/0x8000;
+      halfAxes_[8 + axis + 1].relVal_ = -((float)value)/0x8000;
+      halfAxes_[8 + axis + 1].hasChanged_ = true;
+    }
+  }
 
 
