Implemented basic support for SDL GameController
authorIngo Ruhnke <grumbel@gmail.com>
Wed, 6 Aug 2014 03:39:15 +0000 (05:39 +0200)
committerIngo Ruhnke <grumbel@gmail.com>
Wed, 6 Aug 2014 03:39:15 +0000 (05:39 +0200)
src/control/game_controller_manager.cpp [new file with mode: 0644]
src/control/game_controller_manager.hpp [new file with mode: 0644]
src/control/joystick_manager.cpp
src/control/joystick_manager.hpp
src/control/joystickkeyboardcontroller.cpp
src/control/joystickkeyboardcontroller.hpp

diff --git a/src/control/game_controller_manager.cpp b/src/control/game_controller_manager.cpp
new file mode 100644 (file)
index 0000000..160e598
--- /dev/null
@@ -0,0 +1,204 @@
+//  SuperTux
+//  Copyright (C) 2014 Ingo Ruhnke <grumbel@gmx.de>
+//
+//  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 3 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, see <http://www.gnu.org/licenses/>.
+
+#include "control/game_controller_manager.hpp"
+
+#include <algorithm>
+
+#include "control/joystickkeyboardcontroller.hpp"
+#include "util/log.hpp"
+
+GameControllerManager::GameControllerManager(JoystickKeyboardController* parent) :
+  m_parent(parent),
+  m_deadzone(8000),
+  m_game_controllers()
+{
+}
+
+GameControllerManager::~GameControllerManager()
+{
+  for(auto con : m_game_controllers)
+  {
+    SDL_GameControllerClose(con);
+  }
+}
+
+void
+GameControllerManager::process_button_event(const SDL_ControllerButtonEvent& ev)
+{
+  //log_info << "button event: " << static_cast<int>(ev.button) << " " << static_cast<int>(ev.state) << std::endl;
+  auto controller = m_parent->get_main_controller();
+  switch(ev.button)
+  {
+    case SDL_CONTROLLER_BUTTON_A:
+      controller->set_control(Controller::JUMP, ev.state);
+      controller->set_control(Controller::MENU_SELECT, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_B:
+      break;
+
+    case SDL_CONTROLLER_BUTTON_X:
+      controller->set_control(Controller::ACTION, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_Y:
+      break;
+
+    case SDL_CONTROLLER_BUTTON_BACK:
+      break;
+
+    case SDL_CONTROLLER_BUTTON_GUIDE:
+      controller->set_control(Controller::CONSOLE, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_START:
+      controller->set_control(Controller::PAUSE_MENU, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_LEFTSTICK:
+      break;
+
+    case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
+      break;
+
+    case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
+      controller->set_control(Controller::PEEK_LEFT, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
+      controller->set_control(Controller::PEEK_RIGHT, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_DPAD_UP:
+      controller->set_control(Controller::UP, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
+      controller->set_control(Controller::DOWN, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
+      controller->set_control(Controller::LEFT, ev.state);
+      break;
+
+    case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
+      controller->set_control(Controller::RIGHT, ev.state);
+      break;
+
+    default:
+      break;
+  }
+}
+
+void
+GameControllerManager::process_axis_event(const SDL_ControllerAxisEvent& ev)
+{
+  // FIXME: buttons and axis are fighting for control ownership, need
+  // to OR the values together
+
+  //log_info << "axis event: " << static_cast<int>(ev.axis) << " " << ev.value << std::endl;
+  auto controller = m_parent->get_main_controller();
+  auto axis2button = [this, &controller](int value,
+                                         Controller::Control control_left, Controller::Control control_right)
+    {
+      if (value < -m_deadzone)
+      {
+        controller->set_control(control_left, true);
+        controller->set_control(control_right, false);
+      }
+      else if (value > m_deadzone)
+      {
+        controller->set_control(control_left, false);
+        controller->set_control(control_right, true);
+      }
+      else
+      {
+        controller->set_control(control_left, false);
+        controller->set_control(control_right, false);
+      }
+    };
+
+  switch(ev.axis)
+  {
+    case SDL_CONTROLLER_AXIS_LEFTX:
+      axis2button(ev.value, Controller::LEFT, Controller::RIGHT);
+      break;
+
+    case SDL_CONTROLLER_AXIS_LEFTY:
+      axis2button(ev.value, Controller::UP, Controller::DOWN);
+      break;
+
+    case SDL_CONTROLLER_AXIS_RIGHTX:
+      axis2button(ev.value, Controller::PEEK_LEFT, Controller::PEEK_RIGHT);
+      break;
+
+    case SDL_CONTROLLER_AXIS_RIGHTY:
+      axis2button(ev.value, Controller::PEEK_UP, Controller::PEEK_DOWN);
+      break;
+
+    case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
+      break;
+
+    case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
+      break;
+
+    default:
+      break;
+  }
+}
+
+void
+GameControllerManager::on_controller_added(int joystick_index)
+{
+  if (!SDL_IsGameController(joystick_index))
+  {
+    log_warning << "joystick is not a game controller, ignoring: " << joystick_index << std::endl;
+  }
+  else
+  {
+    SDL_GameController* game_controller = SDL_GameControllerOpen(joystick_index);
+    if (!game_controller)
+    {
+      log_warning << "failed to open game_controller: " << joystick_index
+                  << ": " << SDL_GetError() << std::endl;
+    }
+    else
+    {
+      m_game_controllers.push_back(game_controller);
+    }
+  }
+}
+
+void
+GameControllerManager::on_controller_removed(int instance_id)
+{
+  for(auto& controller : m_game_controllers)
+  {
+    SDL_Joystick* joy = SDL_GameControllerGetJoystick(controller);
+    SDL_JoystickID id = SDL_JoystickInstanceID(joy);
+    if (id == instance_id)
+    {
+      SDL_GameControllerClose(controller);
+      controller = nullptr;
+    }
+  }
+
+  m_game_controllers.erase(std::remove(m_game_controllers.begin(), m_game_controllers.end(), nullptr),
+                           m_game_controllers.end());
+}
+
+/* EOF */
diff --git a/src/control/game_controller_manager.hpp b/src/control/game_controller_manager.hpp
new file mode 100644 (file)
index 0000000..c6fa357
--- /dev/null
@@ -0,0 +1,50 @@
+//  SuperTux
+//  Copyright (C) 2014 Ingo Ruhnke <grumbel@gmx.de>
+//
+//  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 3 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, see <http://www.gnu.org/licenses/>.
+
+#ifndef HEADER_SUPERTUX_CONTROL_GAME_CONTROLLER_MANAGER_HPP
+#define HEADER_SUPERTUX_CONTROL_GAME_CONTROLLER_MANAGER_HPP
+
+#include <vector>
+
+#include "SDL.h"
+
+class JoystickKeyboardController;
+
+class GameControllerManager
+{
+private:
+  JoystickKeyboardController* m_parent;
+  int m_deadzone;
+  std::vector<SDL_GameController*> m_game_controllers;
+
+public:
+  GameControllerManager(JoystickKeyboardController* parent);
+  ~GameControllerManager();
+
+  void process_button_event(const SDL_ControllerButtonEvent& ev);
+  void process_axis_event(const SDL_ControllerAxisEvent& ev);
+
+  void on_controller_added(int joystick_index);
+  void on_controller_removed(int instance_id);
+
+private:
+  GameControllerManager(const GameControllerManager&) = delete;
+  GameControllerManager& operator=(const GameControllerManager&) = delete;
+};
+
+#endif
+
+/* EOF */
index 2c11c96..4d2ba41 100644 (file)
@@ -29,7 +29,6 @@
 
 JoystickManager::JoystickManager(JoystickKeyboardController* parent) :
   parent(parent),
-  m_use_game_controller(true),
   joy_button_map(),
   joy_axis_map(),
   joy_hat_map(),
@@ -41,38 +40,34 @@ JoystickManager::JoystickManager(JoystickKeyboardController* parent) :
   hat_state(0),
   jump_with_up_joy(false),
   wait_for_joystick(-1),
-  joysticks(),
-  game_controllers()
+  joysticks()
 {
-  if (!m_use_game_controller)
-  {
-    // Default joystick button configuration
-    bind_joybutton(0, 0, Controller::JUMP);
-    bind_joybutton(0, 1, Controller::ACTION);
-    // 6 or more Buttons
-    if( min_joybuttons > 5 ){
-      bind_joybutton(0, 4, Controller::PEEK_LEFT);
-      bind_joybutton(0, 5, Controller::PEEK_RIGHT);
-      // 8 or more
-      if(min_joybuttons > 7)
-        bind_joybutton(0, min_joybuttons-1, Controller::PAUSE_MENU);
-    } else {
-      // map the last 2 buttons to menu and pause
-      if(min_joybuttons > 2)
-        bind_joybutton(0, min_joybuttons-1, Controller::PAUSE_MENU);
-      // map all remaining joystick buttons to MENU_SELECT
-      for(int i = 2; i < max_joybuttons; ++i) {
-        if(i != min_joybuttons-1)
-          bind_joybutton(0, i, Controller::MENU_SELECT);
-      }
+  // Default joystick button configuration
+  bind_joybutton(0, 0, Controller::JUMP);
+  bind_joybutton(0, 1, Controller::ACTION);
+  // 6 or more Buttons
+  if( min_joybuttons > 5 ){
+    bind_joybutton(0, 4, Controller::PEEK_LEFT);
+    bind_joybutton(0, 5, Controller::PEEK_RIGHT);
+    // 8 or more
+    if(min_joybuttons > 7)
+      bind_joybutton(0, min_joybuttons-1, Controller::PAUSE_MENU);
+  } else {
+    // map the last 2 buttons to menu and pause
+    if(min_joybuttons > 2)
+      bind_joybutton(0, min_joybuttons-1, Controller::PAUSE_MENU);
+    // map all remaining joystick buttons to MENU_SELECT
+    for(int i = 2; i < max_joybuttons; ++i) {
+      if(i != min_joybuttons-1)
+        bind_joybutton(0, i, Controller::MENU_SELECT);
     }
-
-    // Default joystick axis configuration
-    bind_joyaxis(0, -1, Controller::LEFT);
-    bind_joyaxis(0, 1, Controller::RIGHT);
-    bind_joyaxis(0, -2, Controller::UP);
-    bind_joyaxis(0, 2, Controller::DOWN);
   }
+
+  // Default joystick axis configuration
+  bind_joyaxis(0, -1, Controller::LEFT);
+  bind_joyaxis(0, 1, Controller::RIGHT);
+  bind_joyaxis(0, -2, Controller::UP);
+  bind_joyaxis(0, 2, Controller::DOWN);
 }
 
 JoystickManager::~JoystickManager()
@@ -81,99 +76,52 @@ JoystickManager::~JoystickManager()
   {
     SDL_JoystickClose(joy);
   }
-
-  for(auto con : game_controllers)
-  {
-    SDL_GameControllerClose(con);
-  }
 }
 
 void
 JoystickManager::on_joystick_added(int joystick_index)
 {
   std::cout << "joydeviceadded: " << joystick_index << std::endl;
-  if (m_use_game_controller)
+  SDL_Joystick* joystick = SDL_JoystickOpen(joystick_index);
+  if (!joystick)
   {
-    if (!SDL_IsGameController(joystick_index))
-    {
-      log_warning << "joystick is not a game controller, ignoring: " << joystick_index << std::endl;
-    }
-    else
-    {
-      SDL_GameController* game_controller = SDL_GameControllerOpen(joystick_index);
-      if (!game_controller)
-      {
-        log_warning << "failed to open game_controller: " << joystick_index 
-                    << ": " << SDL_GetError() << std::endl;
-      }
-      else
-      {
-        game_controllers.push_back(game_controller);
-      }
-    }
+    log_warning << "failed to open joystick: " << joystick_index
+                << ": " << SDL_GetError() << std::endl;
   }
   else
   {
-    SDL_Joystick* joystick = SDL_JoystickOpen(joystick_index);
-    if (!joystick)
-    {
-      log_warning << "failed to open joystick: " << joystick_index 
-                  << ": " << SDL_GetError() << std::endl;
-    }
-    else
-    {
-      joysticks.push_back(joystick);
-    }
+    joysticks.push_back(joystick);
+  }
 
-    if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
-      min_joybuttons = SDL_JoystickNumButtons(joystick);
+  if(min_joybuttons < 0 || SDL_JoystickNumButtons(joystick) < min_joybuttons)
+    min_joybuttons = SDL_JoystickNumButtons(joystick);
 
-    if(SDL_JoystickNumButtons(joystick) > max_joybuttons)
-      max_joybuttons = SDL_JoystickNumButtons(joystick);
+  if(SDL_JoystickNumButtons(joystick) > max_joybuttons)
+    max_joybuttons = SDL_JoystickNumButtons(joystick);
 
-    if(SDL_JoystickNumAxes(joystick) > max_joyaxis)
-      max_joyaxis = SDL_JoystickNumAxes(joystick);
+  if(SDL_JoystickNumAxes(joystick) > max_joyaxis)
+    max_joyaxis = SDL_JoystickNumAxes(joystick);
 
-    if(SDL_JoystickNumHats(joystick) > max_joyhats)
-      max_joyhats = SDL_JoystickNumHats(joystick);
-  }
+  if(SDL_JoystickNumHats(joystick) > max_joyhats)
+    max_joyhats = SDL_JoystickNumHats(joystick);
 }
 
 void
 JoystickManager::on_joystick_removed(int instance_id)
 {
-  if (m_use_game_controller)
+  std::cout << "joydeviceremoved: " << static_cast<int>(instance_id) << std::endl;
+  for(auto& joy : joysticks)
   {
-    for(auto& controller : game_controllers)
+    SDL_JoystickID id = SDL_JoystickInstanceID(joy);
+    if (id == instance_id)
     {
-      SDL_Joystick* joy = SDL_GameControllerGetJoystick(controller);
-      SDL_JoystickID id = SDL_JoystickInstanceID(joy);
-      if (id == instance_id)
-      {
-        SDL_GameControllerClose(controller);
-        controller = nullptr;
-      }
+      SDL_JoystickClose(joy);
+      joy = nullptr;
     }
-
-    game_controllers.erase(std::remove(game_controllers.begin(), game_controllers.end(), nullptr),
-                           game_controllers.end());
   }
-  else
-  {
-    std::cout << "joydeviceremoved: " << static_cast<int>(instance_id) << std::endl;
-    for(auto& joy : joysticks)
-    {
-      SDL_JoystickID id = SDL_JoystickInstanceID(joy);
-      if (id == instance_id)
-      {
-        SDL_JoystickClose(joy);
-        joy = nullptr;
-      }
-    }
 
-    joysticks.erase(std::remove(joysticks.begin(), joysticks.end(), nullptr),
-                    joysticks.end());
-  }
+  joysticks.erase(std::remove(joysticks.begin(), joysticks.end(), nullptr),
+                  joysticks.end());
 }
 
 void
@@ -279,7 +227,7 @@ JoystickManager::process_axis_event(const SDL_JoyAxisEvent& jaxis)
 void
 JoystickManager::process_button_event(const SDL_JoyButtonEvent& jbutton)
 {
-  if(wait_for_joystick >= 0) 
+  if(wait_for_joystick >= 0)
   {
     if(jbutton.state == SDL_PRESSED)
     {
@@ -288,8 +236,8 @@ JoystickManager::process_button_event(const SDL_JoyButtonEvent& jbutton)
       parent->reset();
       wait_for_joystick = -1;
     }
-  } 
-  else 
+  }
+  else
   {
     ButtonMap::iterator i = joy_button_map.find(std::make_pair(jbutton.which, jbutton.button));
     if(i == joy_button_map.end()) {
index c0e11d3..f899ffc 100644 (file)
@@ -40,7 +40,6 @@ private:
 
 private:
   JoystickKeyboardController* parent;
-  bool m_use_game_controller;
 
   ButtonMap joy_button_map;
   AxisMap joy_axis_map;
@@ -68,9 +67,6 @@ public:
 public:
   std::vector<SDL_Joystick*> joysticks;
 
-private:
-  std::vector<SDL_GameController*> game_controllers;
-
 public:
   JoystickManager(JoystickKeyboardController* parent);
   ~JoystickManager();
@@ -91,7 +87,7 @@ public:
   void bind_joyaxis(JoyId joy_id, int axis, Controller::Control c);
   void bind_joyhat(JoyId joy_id, int dir, Controller::Control c);
 
-  void set_joy_controls(Controller::Control id, bool value); 
+  void set_joy_controls(Controller::Control id, bool value);
 
   void on_joystick_added(int joystick_index);
   void on_joystick_removed(int instance_id);
index f0740e7..fe695bd 100644 (file)
@@ -20,6 +20,7 @@
 #include <iostream>
 
 #include "control/joystick_manager.hpp"
+#include "control/game_controller_manager.hpp"
 #include "gui/menu_manager.hpp"
 #include "lisp/list_iterator.hpp"
 #include "supertux/console.hpp"
 
 JoystickKeyboardController::JoystickKeyboardController() :
   controller(new Controller),
+  m_use_game_controller(true),
   joystick_manager(new JoystickManager(this)),
+  game_controller_manager(new GameControllerManager(this)),
   keymap(),
-  name(),
   jump_with_up_kbd(),
   wait_for_key(-1)
 {
@@ -155,42 +157,46 @@ JoystickKeyboardController::process_event(const SDL_Event& event)
       break;
 
     case SDL_JOYAXISMOTION:
-      joystick_manager->process_axis_event(event.jaxis);
+      if (!m_use_game_controller) joystick_manager->process_axis_event(event.jaxis);
       break;
 
     case SDL_JOYHATMOTION:
-      joystick_manager->process_hat_event(event.jhat);
+      if (!m_use_game_controller) joystick_manager->process_hat_event(event.jhat);
       break;
 
     case SDL_JOYBUTTONDOWN:
     case SDL_JOYBUTTONUP:
-      joystick_manager->process_button_event(event.jbutton);
+      if (!m_use_game_controller) joystick_manager->process_button_event(event.jbutton);
       break;
 
     case SDL_JOYDEVICEADDED:
-      joystick_manager->on_joystick_added(event.jdevice.which);
+      if (!m_use_game_controller) joystick_manager->on_joystick_added(event.jdevice.which);
       break;
 
     case SDL_JOYDEVICEREMOVED:
-      joystick_manager->on_joystick_removed(event.jdevice.which);
+      if (!m_use_game_controller) joystick_manager->on_joystick_removed(event.jdevice.which);
+      break;
+
+    case SDL_CONTROLLERAXISMOTION:
+      if (m_use_game_controller) game_controller_manager->process_axis_event(event.caxis);
       break;
 
     case SDL_CONTROLLERBUTTONDOWN:
-      std::cout << "SDL_CONTROLLERBUTTONDOWN" << std::endl;
+      if (m_use_game_controller) game_controller_manager->process_button_event(event.cbutton);
       break;
 
     case SDL_CONTROLLERBUTTONUP:
-      std::cout << "SDL_CONTROLLERBUTTONUP" << std::endl;
+      if (m_use_game_controller) game_controller_manager->process_button_event(event.cbutton);
       break;
 
     case SDL_CONTROLLERDEVICEADDED:
-      // ignored, handled in SDL_JOYDEVICEADDED
       std::cout << "SDL_CONTROLLERDEVICEADDED" << std::endl;
+      if (m_use_game_controller) game_controller_manager->on_controller_added(event.cdevice.which);
       break;
 
     case SDL_CONTROLLERDEVICEREMOVED:
-      // ignored, handled in SDL_JOYDEVICEREMOVED
       std::cout << "SDL_CONTROLLERDEVICEREMOVED" << std::endl;
+      if (m_use_game_controller) game_controller_manager->on_controller_removed(event.cdevice.which);
       break;
 
     case SDL_CONTROLLERDEVICEREMAPPED:
index 76798a1..411000b 100644 (file)
 #include "util/reader_fwd.hpp"
 #include "util/writer_fwd.hpp"
 
-class Menu;
-class KeyboardMenu;
-class JoystickMenu;
 class Controller;
+class GameControllerManager;
 class JoystickManager;
+class JoystickMenu;
+class KeyboardMenu;
+class Menu;
 
 class JoystickKeyboardController
 {
@@ -73,13 +74,13 @@ private:
 private:
   std::unique_ptr<Controller> controller;
 public:
+  bool m_use_game_controller;
   std::unique_ptr<JoystickManager> joystick_manager;
+  std::unique_ptr<GameControllerManager> game_controller_manager;
 
 private:
   KeyMap keymap;
 
-  std::string name;
-
   bool jump_with_up_kbd; // Keyboard up jumps
 
   int wait_for_key;