From: Ingo Ruhnke Date: Wed, 6 Aug 2014 03:39:15 +0000 (+0200) Subject: Implemented basic support for SDL GameController X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=f90d0d547f908577a23c922f1cfe9968d7ce86dc;p=supertux.git Implemented basic support for SDL GameController --- diff --git a/src/control/game_controller_manager.cpp b/src/control/game_controller_manager.cpp new file mode 100644 index 000000000..160e598e8 --- /dev/null +++ b/src/control/game_controller_manager.cpp @@ -0,0 +1,204 @@ +// SuperTux +// Copyright (C) 2014 Ingo Ruhnke +// +// 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 . + +#include "control/game_controller_manager.hpp" + +#include + +#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(ev.button) << " " << static_cast(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(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 index 000000000..c6fa357a1 --- /dev/null +++ b/src/control/game_controller_manager.hpp @@ -0,0 +1,50 @@ +// SuperTux +// Copyright (C) 2014 Ingo Ruhnke +// +// 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 . + +#ifndef HEADER_SUPERTUX_CONTROL_GAME_CONTROLLER_MANAGER_HPP +#define HEADER_SUPERTUX_CONTROL_GAME_CONTROLLER_MANAGER_HPP + +#include + +#include "SDL.h" + +class JoystickKeyboardController; + +class GameControllerManager +{ +private: + JoystickKeyboardController* m_parent; + int m_deadzone; + std::vector 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 */ diff --git a/src/control/joystick_manager.cpp b/src/control/joystick_manager.cpp index 2c11c96bc..4d2ba4130 100644 --- a/src/control/joystick_manager.cpp +++ b/src/control/joystick_manager.cpp @@ -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(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(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()) { diff --git a/src/control/joystick_manager.hpp b/src/control/joystick_manager.hpp index c0e11d3de..f899ffce5 100644 --- a/src/control/joystick_manager.hpp +++ b/src/control/joystick_manager.hpp @@ -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 joysticks; -private: - std::vector 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); diff --git a/src/control/joystickkeyboardcontroller.cpp b/src/control/joystickkeyboardcontroller.cpp index f0740e79e..fe695bde7 100644 --- a/src/control/joystickkeyboardcontroller.cpp +++ b/src/control/joystickkeyboardcontroller.cpp @@ -20,6 +20,7 @@ #include #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" @@ -32,9 +33,10 @@ 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: diff --git a/src/control/joystickkeyboardcontroller.hpp b/src/control/joystickkeyboardcontroller.hpp index 76798a194..411000bbb 100644 --- a/src/control/joystickkeyboardcontroller.hpp +++ b/src/control/joystickkeyboardcontroller.hpp @@ -28,11 +28,12 @@ #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; public: + bool m_use_game_controller; std::unique_ptr joystick_manager; + std::unique_ptr game_controller_manager; private: KeyMap keymap; - std::string name; - bool jump_with_up_kbd; // Keyboard up jumps int wait_for_key;