Messaging subsystem rewrite, step I
[supertux.git] / src / control / joystickkeyboardcontroller.cpp
index 83cbdbc..cffa6f5 100644 (file)
 //  along with this program; if not, write to the Free Software
 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 //  02111-1307, USA.
-
 #include <config.h>
 
 #include <sstream>
-#include "joystickkeyboardcontroller.h"
-#include "gui/menu.h"
-#include "app/gettext.h"
-#include "lisp/lisp.h"
-#include "lisp/list_iterator.h"
-#include "game_session.h"
+#include "joystickkeyboardcontroller.hpp"
+#include "msg.hpp"
+#include "gui/menu.hpp"
+#include "gettext.hpp"
+#include "lisp/lisp.hpp"
+#include "lisp/list_iterator.hpp"
+#include "game_session.hpp"
+#include "console.hpp"
 
 class JoystickKeyboardController::JoystickMenu : public Menu
 {
@@ -53,10 +54,9 @@ public:
 };
   
 JoystickKeyboardController::JoystickKeyboardController()
-  : wait_for_key(-1), wait_for_joybutton(-1)
+  : wait_for_key(-1), wait_for_joybutton(-1), key_options_menu(0),
+    joystick_options_menu(0)
 {
-       memset(last_keys, 0, sizeof(last_keys));
-
   // initialize default keyboard map
   keymap.insert(std::make_pair(SDLK_LEFT, LEFT));
   keymap.insert(std::make_pair(SDLK_RIGHT, RIGHT));
@@ -70,29 +70,25 @@ JoystickKeyboardController::JoystickKeyboardController()
   keymap.insert(std::make_pair(SDLK_PAUSE, PAUSE_MENU));  
   keymap.insert(std::make_pair(SDLK_RETURN, MENU_SELECT));
   keymap.insert(std::make_pair(SDLK_KP_ENTER, MENU_SELECT));
+  keymap.insert(std::make_pair(SDLK_CARET, CONSOLE));
   
-  joystick_count = SDL_NumJoysticks();
+  int joystick_count = SDL_NumJoysticks();
   min_joybuttons = -1;
   max_joybuttons = -1;
-#ifdef DEBUG
-  std::cout << "Found " << joystick_count << " joysticks.\n";
-#endif
   for(int i = 0; i < joystick_count; ++i) {
     SDL_Joystick* joystick = SDL_JoystickOpen(i);
     bool good = true;
     if(SDL_JoystickNumButtons(joystick) < 2) {
-      std::cerr << "Joystick " << i << " has less than 2 buttons.\n";
+      msg_warning << "Joystick " << i << " has less than 2 buttons" << std::endl;
       good = false;
     }
     if(SDL_JoystickNumAxes(joystick) < 2
        && SDL_JoystickNumHats(joystick) == 0) {
-      std::cerr << "Joystick " << i << " has less than 2 axes and no hat.\n";
+      msg_warning << "Joystick " << i << " has less than 2 axes and no hat" << std::endl;
       good = false;
     }
     if(!good) {
       SDL_JoystickClose(joystick);
-      joysticks.push_back(0);
-      joystick_names.push_back("");
       continue;
     }
     
@@ -102,7 +98,6 @@ JoystickKeyboardController::JoystickKeyboardController()
       max_joybuttons = SDL_JoystickNumButtons(joystick);
     }
 
-    joystick_names.push_back(SDL_JoystickName(i));
     joysticks.push_back(joystick);
   }
 
@@ -122,6 +117,13 @@ JoystickKeyboardController::JoystickKeyboardController()
     if(i != min_joybuttons-1)
       joy_button_map.insert(std::make_pair(i, MENU_SELECT));
   }
+
+  // some joysticks or SDL seem to produce some bogus events after being opened
+  Uint32 ticks = SDL_GetTicks();
+  while(SDL_GetTicks() - ticks < 200) {
+    SDL_Event event;
+    SDL_PollEvent(&event);
+  }
 }
 
 JoystickKeyboardController::~JoystickKeyboardController()
@@ -151,7 +153,7 @@ JoystickKeyboardController::read(const lisp::Lisp& lisp)
         map->get("key", key);
         map->get("control", control);
         if(key < SDLK_FIRST || key >= SDLK_LAST) {
-          std::cerr << "Invalid key '" << key << "' in keymap.\n";
+          msg_warning << "Invalid key '" << key << "' in keymap" << std::endl;
           continue;
         }
 
@@ -161,12 +163,12 @@ JoystickKeyboardController::read(const lisp::Lisp& lisp)
             break;
         }
         if(controlNames[i] == 0) {
-          std::cerr << "Invalid control '" << control << "' in keymap.\n";
+          msg_warning << "Invalid control '" << control << "' in keymap" << std::endl;
           continue;
         }
         keymap.insert(std::make_pair((SDLKey) key, (Control) i));
       } else {
-        std::cerr << "Invalid lisp element '" << iter.item() << "' in keymap.\n";
+        msg_warning << "Invalid lisp element '" << iter.item() << "' in keymap" << std::endl;
       }
     }
   }
@@ -187,7 +189,7 @@ JoystickKeyboardController::read(const lisp::Lisp& lisp)
         map->get("button", button);
         map->get("control", control);
         if(button < 0 || button >= max_joybuttons) {
-          std::cerr << "Invalid button '" << button << "' in buttonmap.\n";
+          msg_warning << "Invalid button '" << button << "' in buttonmap" << std::endl;
           continue;
         }
         
@@ -197,7 +199,7 @@ JoystickKeyboardController::read(const lisp::Lisp& lisp)
             break;
         }                                                                           
         if(controlNames[i] == 0) {
-          std::cerr << "Invalid control '" << control << "' in buttonmap.\n";
+          msg_warning << "Invalid control '" << control << "' in buttonmap" << std::endl;
           continue;
         }
         reset_joybutton(button, (Control) i);
@@ -234,36 +236,18 @@ JoystickKeyboardController::write(lisp::Writer& writer)
 }
 
 void
+JoystickKeyboardController::reset()
+{
+  Controller::reset();
+}
+
+void
 JoystickKeyboardController::process_event(const SDL_Event& event)
 {
   switch(event.type) {
     case SDL_KEYUP:
     case SDL_KEYDOWN:
-      // remember ascii keys for cheat codes...
-      if(event.type == SDL_KEYDOWN && 
-          (event.key.keysym.unicode & 0xFF80) == 0) {
-        memmove(last_keys, last_keys+1, sizeof(last_keys)-1);
-        last_keys[sizeof(last_keys)-1] = event.key.keysym.unicode;
-        if(GameSession::current())
-          GameSession::current()->try_cheats();
-      }
-                       
-      // menu mode?
-      if(Menu::current()) { // menu mode
-        process_menu_key_event(event);
-        return;
-      } else {
-        // normal mode, find key in keymap
-        KeyMap::iterator i = keymap.find(event.key.keysym.sym);
-        if(i == keymap.end()) {
-#ifdef DEBUG
-          std::cerr << "Pressed key without mapping.\n";
-#endif
-          return;
-        }
-        Control control = i->second;
-        controls[control] = event.type == SDL_KEYDOWN ? true : false;
-      }
+      process_key_event(event);
       break;
 
     case SDL_JOYAXISMOTION:
@@ -337,10 +321,7 @@ JoystickKeyboardController::process_event(const SDL_Event& event)
 
       ButtonMap::iterator i = joy_button_map.find(event.jbutton.button);
       if(i == joy_button_map.end()) {
-#ifdef DEBUG
-        std::cerr << "Unmapped joybutton " << (int) event.jbutton.button
-          << " pressed.\n";
-#endif
+        msg_debug << "Unmapped joybutton " << (int)event.jbutton.button << " pressed" << std::endl;
         return;
       }
       
@@ -355,6 +336,72 @@ JoystickKeyboardController::process_event(const SDL_Event& event)
 }
 
 void
+JoystickKeyboardController::process_key_event(const SDL_Event& event)
+{
+  KeyMap::iterator key_mapping = keymap.find(event.key.keysym.sym);
+
+  // if console key was pressed: toggle console
+  if ((key_mapping != keymap.end()) && (key_mapping->second == CONSOLE)) {
+    if (event.type != SDL_KEYDOWN) return;
+    Console::toggle();
+    return;
+  }
+
+  // if console is open: send key there
+  if (Console::hasFocus()) {
+    process_console_key_event(event);
+    return;
+  } 
+
+  // if menu mode: send key there
+  if (Menu::current()) { 
+    process_menu_key_event(event);
+    return;
+  }
+
+  // default action: update controls
+  if(key_mapping == keymap.end()) {
+    msg_debug << "Key " << event.key.keysym.sym << " is unbound" << std::endl;
+    return;
+  }
+  Control control = key_mapping->second;
+  controls[control] = event.type == SDL_KEYDOWN ? true : false;
+}
+
+void
+JoystickKeyboardController::process_console_key_event(const SDL_Event& event)
+{
+  if (event.type != SDL_KEYDOWN) return;
+
+  switch (event.key.keysym.sym) {
+    case SDLK_RETURN:
+      Console::input << std::endl;
+      break;
+    case SDLK_BACKSPACE:
+      Console::backspace();
+      break;
+    case SDLK_TAB:
+      Console::autocomplete();
+      break;
+    case SDLK_PAGEUP:
+      Console::scroll(-1);
+      break;
+    case SDLK_PAGEDOWN:
+      Console::scroll(+1);
+      break;
+    case SDLK_END:
+      Console::scroll(+65535);
+      break;
+    default:
+      int c = event.key.keysym.unicode;
+      if ((c >= 32) && (c <= 126)) {
+       Console::input << (char)c;
+      }
+      break;
+  }
+}
+
+void
 JoystickKeyboardController::process_menu_key_event(const SDL_Event& event)
 {
   // wait for key mode?
@@ -510,23 +557,6 @@ JoystickKeyboardController::get_joystick_options_menu()
   return joystick_options_menu;
 }
 
-bool
-JoystickKeyboardController::check_cheatcode(const std::string& cheatcode)
-{
-  if(cheatcode.size() > sizeof(last_keys)) {
-#ifdef DEBUG
-    std::cerr << "Cheat Code too long.\n";
-#endif
-    return false;
-  }
-
-  for(int i = 0; i < cheatcode.size(); ++i) {
-    if(last_keys[sizeof(last_keys)-1 - i] != cheatcode[cheatcode.size()-1-i])
-      return false;
-  }
-  return true;
-}
-
 //----------------------------------------------------------------------------
 
 JoystickKeyboardController::KeyboardMenu::KeyboardMenu(
@@ -618,9 +648,13 @@ JoystickKeyboardController::JoystickMenu::JoystickMenu(
 {
   add_label(_("Joystick Setup"));
   add_hl();
-  add_controlfield(Controller::JUMP, _("Jump"));
-  add_controlfield(Controller::ACTION, _("Shoot/Run"));
-  add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
+  if(controller->joysticks.size() > 0) {
+    add_controlfield(Controller::JUMP, _("Jump"));
+    add_controlfield(Controller::ACTION, _("Shoot/Run"));
+    add_controlfield(Controller::PAUSE_MENU, _("Pause/Menu"));
+  } else {
+    add_deactive(-1, _("No Joysticks found"));
+  }
   add_hl();
   add_back(_("Back"));
   update();
@@ -651,6 +685,9 @@ JoystickKeyboardController::JoystickMenu::menu_action(MenuItem* item)
 void
 JoystickKeyboardController::JoystickMenu::update()
 {
+  if(controller->joysticks.size() == 0)
+    return;
+
   // update menu
   get_item_by_id((int) Controller::JUMP).change_input(get_button_name(
     controller->reversemap_joybutton(Controller::JUMP)));