--- /dev/null
+// 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 */
--- /dev/null
+// 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 */
JoystickManager::JoystickManager(JoystickKeyboardController* parent) :
parent(parent),
- m_use_game_controller(true),
joy_button_map(),
joy_axis_map(),
joy_hat_map(),
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()
{
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
void
JoystickManager::process_button_event(const SDL_JoyButtonEvent& jbutton)
{
- if(wait_for_joystick >= 0)
+ if(wait_for_joystick >= 0)
{
if(jbutton.state == SDL_PRESSED)
{
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()) {
private:
JoystickKeyboardController* parent;
- bool m_use_game_controller;
ButtonMap joy_button_map;
AxisMap joy_axis_map;
public:
std::vector<SDL_Joystick*> joysticks;
-private:
- std::vector<SDL_GameController*> game_controllers;
-
public:
JoystickManager(JoystickKeyboardController* parent);
~JoystickManager();
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);
#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)
{
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:
#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
{
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;