From 9ba0bd67d2b6e5454d10fab8743c14b669ae1ed6 Mon Sep 17 00:00:00 2001 From: rforder Date: Thu, 6 Aug 2009 18:00:18 +0000 Subject: [PATCH] Added new DeviceConfig class (/config/device_config.cpp) for review. The DeviceConfig class will be responsibile for handling Gamepad and Keyboard configurations. It is now possible to share a single configuration between identical devices. Begun integration, still needs *a lot* of cleanup, but basically works. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/branches/irrlicht@3814 178a84e3-b1eb-0310-8ba1-8eac791a3b58 --- src/Makefile.am | 2 + src/config/device_config.cpp | 267 +++++++++++++++++++++++++++++++++++ src/config/device_config.hpp | 96 +++++++++++++ src/input/device_manager.cpp | 86 ++++++----- src/input/device_manager.hpp | 9 +- src/input/input_device.cpp | 53 +++---- src/input/input_device.hpp | 18 +-- src/input/input_manager.cpp | 1 - 8 files changed, 447 insertions(+), 85 deletions(-) create mode 100644 src/config/device_config.cpp create mode 100644 src/config/device_config.hpp diff --git a/src/Makefile.am b/src/Makefile.am index 618ac65f8..14d036f9d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,6 +46,8 @@ supertuxkart_SOURCES = \ config/stk_config.hpp \ config/user_config.cpp \ config/user_config.hpp \ + config/device_config.cpp \ + config/device_config.hpp \ graphics/camera.cpp \ graphics/camera.hpp \ graphics/explosion.cpp \ diff --git a/src/config/device_config.cpp b/src/config/device_config.cpp new file mode 100644 index 000000000..2ef589f37 --- /dev/null +++ b/src/config/device_config.cpp @@ -0,0 +1,267 @@ +#include "config/device_config.hpp" + +//==== D E V I C E C O N F I G ================================================= + +std::string DeviceConfig::getBindingAsString (const PlayerAction action) const +{ + std::string returnString = NULL; + + if ((action < PA_COUNT) && (action >= 0)) + { + returnString = Input::getInputAsString(m_bindings[action].type, + m_bindings[action].id, + m_bindings[action].dir); + } + + return returnString; +} + +//------------------------------------------------------------------------------ + +std::string DeviceConfig::toString () +{ + std::string returnString = ""; + for (int n = 0; n < PA_COUNT; n++) + { + returnString = returnString.append(KartActionStrings[n]); + returnString = returnString.append(": "); + returnString = returnString.append(Input::getInputAsString(m_bindings[n].type, + m_bindings[n].id, + m_bindings[n].dir)); + returnString = returnString.append("\n"); + } + return returnString; +} + +//------------------------------------------------------------------------------ + +void DeviceConfig::setBinding ( const PlayerAction action, + const Input::InputType type, + const int id, + Input::AxisDirection direction ) +{ + m_bindings[action].type = type; + m_bindings[action].id = id; + m_bindings[action].dir = direction; +} + +//------------------------------------------------------------------------------ + +bool DeviceConfig::getBinding ( Input::InputType type, + const int id, + const int value, + PlayerAction* action ) +{ + bool success = false; + int n; + + for (n = 0; ((n < PA_COUNT) && (!success)); n++) + { + if ((m_bindings[n].type == type) && (m_bindings[n].id == id)) + { + + if (type == Input::IT_STICKMOTION) + { + if ((m_bindings[n].dir == Input::AD_POSITIVE) && (value > 0) || + (m_bindings[n].dir == Input::AD_NEGATIVE) && (value < 0)) + { + success = true; + *action = (PlayerAction)n; + } + } + else + { + success = true; + *action = (PlayerAction)n; + } + } + } // end for n + + return success; +} + +//------------------------------------------------------------------------------ + +void DeviceConfig::serialize (std::ofstream& stream) +{ + for(int n=0; n\n"; + } +} + +//------------------------------------------------------------------------------ + +bool DeviceConfig::deserializeAction(irr::io::IrrXMLReader* xml) +{ + bool success = false; + int binding_id = -1; + int id; + Input::InputType type; + Input::AxisDirection dir; + + // Never hurts to check ;) + if (xml == NULL) + { + fprintf(stderr, "Error: null pointer (DeviceConfig::deserializeAction)\n"); + } + else + { + // Read tags from XML + const char *name_string = xml->getAttributeValue("name"); + const char *id_string = xml->getAttributeValue("id"); + const char *event_string = xml->getAttributeValue("event"); + const char *dir_string = xml->getAttributeValue("direction"); + + // Proceed only if neccesary tags were found + if ((name_string != NULL) && (id_string != NULL) && + (event_string != NULL)) + { + // Convert strings to string tags to integer types + type = (Input::InputType)atoi(event_string); + id = atoi(id_string); + + // Try to determine action # for verbose action name + for (int n = 0; ((n < PA_COUNT) && (binding_id == -1)); n++) + { + if (strcmp(name_string, KartActionStrings[n].c_str()) == 0) + binding_id = n; + } + + // If action # was found then store the bind + if (binding_id != -1) + { + // If the action is not a stick motion (button or key) + if (type != Input::IT_STICKMOTION) + { + setBinding((PlayerAction)binding_id, type, id); + success = true; + } + + // If the action is a stick motion & a direction is defined + else if (dir_string != NULL) + { + dir = (Input::AxisDirection)atoi(dir_string); + setBinding((PlayerAction)binding_id, type, id, dir); + success = true; + } + else + { + printf("WARNING: IT_STICKMOTION without direction, ignoring.\n"); + } + } // end if binding_id != -1 + } // end if name_string != NULL ... + } // end if xml == NULL ... else + + return success; +} + + +// KeyboardConfig & GamepadConfig classes really should be in a separate cpp +// file but they are so small that we'll just leave them here for now. + +//==== K E Y B O A R D C O N F I G ============================================= + +void KeyboardConfig::serialize (std::ofstream& stream) +{ + stream << "\n\n"; + DeviceConfig::serialize(stream); + stream << "\n\n\n"; +} + +//------------------------------------------------------------------------------ + +void KeyboardConfig::setDefaultBinds() +{ + setBinding(PA_NITRO, Input::IT_KEYBOARD, KEY_KEY_N); + setBinding(PA_ACCEL, Input::IT_KEYBOARD, KEY_UP); + setBinding(PA_BRAKE, Input::IT_KEYBOARD, KEY_DOWN); + setBinding(PA_LEFT, Input::IT_KEYBOARD, KEY_LEFT); + setBinding(PA_RIGHT, Input::IT_KEYBOARD, KEY_RIGHT); + setBinding(PA_DRIFT, Input::IT_KEYBOARD, KEY_KEY_V); + setBinding(PA_RESCUE, Input::IT_KEYBOARD, KEY_BACK); + setBinding(PA_FIRE, Input::IT_KEYBOARD, KEY_SPACE); + setBinding(PA_LOOK_BACK, Input::IT_KEYBOARD, KEY_KEY_B); +} + +//------------------------------------------------------------------------------ + +KeyboardConfig::KeyboardConfig() +{ + setDefaultBinds(); +} + +//==== G A M E P A D C O N F I G =============================================== + +void GamepadConfig::serialize (std::ofstream& stream) +{ + stream << "\n\n"; + DeviceConfig::serialize(stream); + stream << "\n\n\n"; +} + +//------------------------------------------------------------------------------ + +void GamepadConfig::setDefaultBinds () +{ + setBinding(PA_LEFT, Input::IT_STICKMOTION, 0, Input::AD_NEGATIVE); + setBinding(PA_RIGHT, Input::IT_STICKMOTION, 0, Input::AD_POSITIVE); + setBinding(PA_ACCEL, Input::IT_STICKMOTION, 1, Input::AD_NEGATIVE); + setBinding(PA_BRAKE, Input::IT_STICKMOTION, 1, Input::AD_POSITIVE); + setBinding(PA_FIRE, Input::IT_STICKBUTTON, 0); + setBinding(PA_NITRO, Input::IT_STICKBUTTON, 1); + setBinding(PA_DRIFT, Input::IT_STICKBUTTON, 2); + setBinding(PA_RESCUE, Input::IT_STICKBUTTON, 3); + setBinding(PA_LOOK_BACK, Input::IT_STICKBUTTON, 4); + //TODO - mappings for clear/enter/leave GA_CLEAR_MAPPING, GA_ENTER, GA_LEAVE? +} + +//------------------------------------------------------------------------------ + +GamepadConfig::GamepadConfig ( const std::string name, + const int axis_count, + const int btnCount ) +{ + m_name = name; + m_axis_count = axis_count; + m_button_count = btnCount; + setDefaultBinds(); +} + +//------------------------------------------------------------------------------ + +GamepadConfig::GamepadConfig(irr::io::IrrXMLReader* xml) +{ + const char* name_string = xml->getAttributeValue("name"); + if(name_string == NULL) + { + printf("ERROR: Unnamed joystick in config file\n"); + } + else + { + m_name = name_string; + } +} + +//------------------------------------------------------------------------------ + +std::string GamepadConfig::toString () +{ + std::string returnString = ""; + returnString = returnString.append(getName()); + returnString = returnString.append("\n"); + returnString = returnString.append(DeviceConfig::toString()); + return returnString; +} diff --git a/src/config/device_config.hpp b/src/config/device_config.hpp new file mode 100644 index 000000000..0bac79f2e --- /dev/null +++ b/src/config/device_config.hpp @@ -0,0 +1,96 @@ +#ifndef DEVICE_CONFIG_HPP +#define DEVICE_CONFIG_HPP + +#include +#include "input/input.hpp" +#include +#include +#include "io/xml_node.hpp" + + +struct KeyBinding +{ + + Input::InputType type; + int id; + Input::AxisDirection dir; + +}; + + +//==== D E V I C E C O N F I G ================================================= + +class DeviceConfig +{ + private: + + KeyBinding m_bindings[PA_COUNT]; + + protected: + + public: + + std::string getBindingAsString (const PlayerAction action) const; + std::string toString (); + + void serialize (std::ofstream& stream); + bool deserializeAction (irr::io::IrrXMLReader* xml); + + void setBinding (const PlayerAction action, + const Input::InputType type, + const int id, + Input::AxisDirection direction = Input::AD_NEUTRAL); + + bool getBinding (Input::InputType type, + const int id, + const int value, + PlayerAction* action); + +}; + +//==== K E Y B O A R D C O N F I G ============================================= + +class KeyboardConfig : public DeviceConfig +{ + private: + + protected: + + public: + + void setDefaultBinds (); + void serialize (std::ofstream& stream); + +// KeyboardConfig (irr::io::IrrXMLReader* xml); + KeyboardConfig (); +}; + + +//==== G A M E P A D C O N F I G =============================================== + +class GamepadConfig : public DeviceConfig +{ + + private: + + std::string m_name; + int m_axis_count; + int m_button_count; + + public: + + std::string toString (); + std::string getName() const { return m_name; }; + int getAxisCount() const { return m_axis_count; }; + int getButtonCount() const { return m_button_count; }; + void serialize (std::ofstream& stream); + void setDefaultBinds (); + GamepadConfig (irr::io::IrrXMLReader* xml); + GamepadConfig (const std::string name, + const int axis_count, + const int btnCount); +// ~GamepadConfig(); + +}; + +#endif diff --git a/src/input/device_manager.cpp b/src/input/device_manager.cpp index e047699c8..045b5b3ee 100644 --- a/src/input/device_manager.cpp +++ b/src/input/device_manager.cpp @@ -12,7 +12,8 @@ DeviceManager::DeviceManager() { - m_keyboard_amount = 0; + m_keyboards.push_back(new KeyboardDevice()); + m_keyboard_amount = m_keyboards.size(); m_gamepad_amount = 0; m_latest_used_device = NULL; m_assign_mode = NO_ASSIGN; @@ -20,24 +21,24 @@ DeviceManager::DeviceManager() // ----------------------------------------------------------------------------- bool DeviceManager::initGamePadSupport() { + GamepadConfig *gamepadConfig; + bool something_new_to_write = true; + // Prepare a list of connected joysticks. std::cout << "====================\nGamePad/Joystick detection and configuration\n====================\n"; irr_driver->getDevice()->activateJoysticks(m_irrlicht_gamepads); + const int numSticks = m_irrlicht_gamepads.size(); - const int numSticks = m_irrlicht_gamepads.size(); std::cout << "irrLicht detects " << numSticks << " gamepads" << std::endl; - - bool something_new_to_write = false; - - // check if it's a new gamepad. If so, add it to the file. + for (int i = 0; i < numSticks; i++) { std::cout << m_irrlicht_gamepads[i].Name.c_str() << " : " << m_irrlicht_gamepads[i].Axes << " axes , " << m_irrlicht_gamepads[i].Buttons << " buttons\n"; - - if(checkForGamePad(i)) something_new_to_write = true; + gamepadConfig = getGamepadConfig(i); + add(new GamePadDevice(i, m_irrlicht_gamepads[i].Name.c_str(), m_irrlicht_gamepads[i].Axes, m_irrlicht_gamepads[i].Buttons, gamepadConfig)); } std::cout << "====================\n"; @@ -78,32 +79,36 @@ GamePadDevice* DeviceManager::getGamePadFromIrrID(const int id) } // ----------------------------------------------------------------------------- /** - * Check if we already have a config object for joystick 'irr_id' as reported by irrLicht - * If yes, 'open' the gamepad. If no, create one. Returns whether a new gamepad was created. + * Check if we already have a config object for gamepad 'irr_id' as reported by irrLicht + * If yes, return a pointer to the configuration. If no, create one. Returns pointer. */ -bool DeviceManager::checkForGamePad(const int irr_id) +GamepadConfig *DeviceManager::getGamepadConfig(const int irr_id) { std::string name = m_irrlicht_gamepads[irr_id].Name.c_str(); + GamepadConfig *config = NULL; - std::cout << "trying to find gamepad " << name.c_str() << std::endl; + std::cout << "trying to find gamepad configuration" << name.c_str() << std::endl; - for(unsigned int n=0; n that's the one currently connected\n"; - m_gamepads[n].open(irr_id, m_gamepads[n].m_name, m_irrlicht_gamepads[irr_id].Axes, m_irrlicht_gamepads[irr_id].Buttons); - return false; + config = m_gamepad_configs.get(n); } } - std::cout << "couldn't find this joystick, so creating a new one" << std::endl; - add(new GamePadDevice(irr_id, m_irrlicht_gamepads[irr_id].Name.c_str(), m_irrlicht_gamepads[irr_id].Axes, m_irrlicht_gamepads[irr_id].Buttons )); - return true; + if (config == NULL) + { + std::cout << "couldn't find a configuration for this gamepad, creating one" << std::endl; + config = new GamepadConfig(m_irrlicht_gamepads[irr_id].Name.c_str(), m_irrlicht_gamepads[irr_id].Axes, m_irrlicht_gamepads[irr_id].Buttons); + m_gamepad_configs.push_back(config); + } + return config; } // ----------------------------------------------------------------------------- void DeviceManager::add(KeyboardDevice* d) @@ -295,8 +300,8 @@ bool DeviceManager::deserialize() int reading_now = NOTHING; - KeyboardDevice* keyboard_device; - GamePadDevice* gamepad_device; + KeyboardConfig* keyboard_config = NULL; + GamepadConfig* gamepad_config = NULL; // parse XML file while(xml && xml->read()) @@ -310,25 +315,27 @@ bool DeviceManager::deserialize() { if (strcmp("keyboard", xml->getNodeName()) == 0) { - keyboard_device = new KeyboardDevice(xml); + keyboard_config = new KeyboardConfig(); reading_now = KEYBOARD; } else if (strcmp("gamepad", xml->getNodeName()) == 0) { - gamepad_device = new GamePadDevice(xml); + gamepad_config = new GamepadConfig(xml); reading_now = GAMEPAD; } else if (strcmp("action", xml->getNodeName()) == 0) { if(reading_now == KEYBOARD) { - if(!keyboard_device->deserializeAction(xml)) - std::cerr << "Ignoring an ill-formed action in input config\n"; + if(keyboard_config != NULL) + if(!keyboard_config->deserializeAction(xml)) + std::cerr << "Ignoring an ill-formed action in input config\n"; } else if(reading_now == GAMEPAD) { - if(!gamepad_device->deserializeAction(xml)) - std::cerr << "Ignoring an ill-formed action in input config\n"; + if(gamepad_config != NULL) + if(!gamepad_config->deserializeAction(xml)) + std::cerr << "Ignoring an ill-formed action in input config\n"; } else std::cerr << "Warning: An action is placed in an unexpected area in the input config file\n"; } @@ -339,13 +346,13 @@ bool DeviceManager::deserialize() { if (strcmp("keyboard", xml->getNodeName()) == 0) { - add(keyboard_device); + m_keyboard_configs.push_back(keyboard_config); reading_now = NOTHING; } else if (strcmp("gamepad", xml->getNodeName()) == 0) { - add(gamepad_device); - reading_now = GAMEPAD; + m_gamepad_configs.push_back(gamepad_config); + reading_now = NOTHING; } } break; @@ -354,6 +361,15 @@ bool DeviceManager::deserialize() } // end switch } // end while + + if (m_keyboard_configs.size() == 0) + m_keyboard_configs.push_back(new KeyboardConfig()); + + for (int n = 0; n < m_keyboard_configs.size(); n++) + printf("%s\n", m_keyboard_configs[n].toString().c_str()); + + for (int n = 0; n < m_gamepad_configs.size(); n++) + printf("%s\n", m_gamepad_configs[n].toString().c_str()); return true; } @@ -377,13 +393,13 @@ void DeviceManager::serialize() configfile << "\n\n"; - for(unsigned int n=0; n\n"; diff --git a/src/input/device_manager.hpp b/src/input/device_manager.hpp index a9c47b450..1dd3e4dda 100644 --- a/src/input/device_manager.hpp +++ b/src/input/device_manager.hpp @@ -2,6 +2,7 @@ #define DEVICE_MANAGER_HPP #include "input/input_device.hpp" +#include "config/device_config.hpp" #include "utils/ptr_vector.hpp" enum PlayerAssignMode @@ -13,8 +14,10 @@ enum PlayerAssignMode class DeviceManager { - ptr_vector m_keyboards; - ptr_vector m_gamepads; + ptr_vector m_keyboards; + ptr_vector m_gamepads; + ptr_vector m_keyboard_configs; + ptr_vector m_gamepad_configs; core::array m_irrlicht_gamepads; @@ -60,7 +63,7 @@ public: /* returns whether a new gamepad was detected */ bool initGamePadSupport(); - bool checkForGamePad(const int sdl_id); + GamepadConfig *getGamepadConfig(const int sdl_id); }; diff --git a/src/input/input_device.cpp b/src/input/input_device.cpp index 63b162e72..de9ce6310 100644 --- a/src/input/input_device.cpp +++ b/src/input/input_device.cpp @@ -1,10 +1,12 @@ #include "states_screens/state_manager.hpp" +#include "config/device_config.hpp" #include "input/input.hpp" #include "input/input_device.hpp" #include "modes/world.hpp" #include "race/race_manager.hpp" + InputDevice::InputDevice() { for(int n=0; ngetBinding(Input::IT_KEYBOARD, key_id, 0, action); } // ----------------------------------------------------------------------------- @@ -193,11 +203,15 @@ GamePadDevice::GamePadDevice(irr::io::IrrXMLReader* xml) * (defaults will be used) * \param sdlIndex Index of stick. */ -GamePadDevice::GamePadDevice(const int irrIndex, const std::string name, const int axis_count, const int btnAmount) +GamePadDevice::GamePadDevice(const int irrIndex, const std::string name, const int axis_count, const int btnAmount, GamepadConfig *configuration) { m_type = DT_GAMEPAD; m_deadzone = DEADZONE_JOYSTICK; m_prevAxisDirections = NULL; + m_configuration = configuration; + + printf("New Gamepad Created. Assigned the following configuration:\n%s", m_configuration->toString().c_str()); + open(irrIndex, name, axis_count, btnAmount); m_name = name; @@ -365,40 +379,9 @@ bool GamePadDevice::hasBinding(Input::InputType type, const int id, const int va return false; } - - // find corresponding action and return it - for(int n=0; n 0) - { - *action = (PlayerAction)n; - return true; - } - } - }// next device - - } - else if(type == Input::IT_STICKBUTTON) - { - // find corresponding action and return it - for(int n=0; ngetBinding(type, id, value, action); } // ----------------------------------------------------------------------------- /** Destructor for GamePadDevice. diff --git a/src/input/input_device.hpp b/src/input/input_device.hpp index 686990bff..188e10843 100644 --- a/src/input/input_device.hpp +++ b/src/input/input_device.hpp @@ -3,6 +3,7 @@ #include #include "input/input.hpp" +#include "config/device_config.hpp" #include #include #include "io/xml_node.hpp" @@ -15,16 +16,6 @@ enum DeviceType DT_GAMEPAD }; -struct KeyBinding -{ - Input::InputType type; - - // key for keyboards, axis for gamepads - int id; - - Input::AxisDirection dir; // for gamepads -}; - class InputDevice { friend class DeviceManager; @@ -55,7 +46,10 @@ public: class KeyboardDevice : public InputDevice { public: + KeyboardConfig *m_configuration; + KeyboardDevice(); + KeyboardDevice(KeyboardConfig *configuration); KeyboardDevice(irr::io::IrrXMLReader* xml); /** checks if this key belongs to this belongs. if yes, sets action and returns true; otherwise returns false */ @@ -70,7 +64,9 @@ class GamePadDevice : public InputDevice { void resetAxisDirection(const int axis, Input::AxisDirection direction, ActivePlayer* player); bool m_buttonPressed[SEvent::SJoystickEvent::NUMBER_OF_BUTTONS]; + public: + GamepadConfig *m_configuration; int m_deadzone; int m_index; int m_axis_count; @@ -88,7 +84,7 @@ public: void loadDefaults(); - GamePadDevice(const int irrIndex, const std::string name, const int axis_number, const int btnAmount); + GamePadDevice(const int irrIndex, const std::string name, const int axis_number, const int btnAmount, GamepadConfig *configuration); GamePadDevice(irr::io::IrrXMLReader* xml); bool isButtonPressed(const int i); diff --git a/src/input/input_manager.cpp b/src/input/input_manager.cpp index 4ed7c8422..89f876201 100644 --- a/src/input/input_manager.cpp +++ b/src/input/input_manager.cpp @@ -65,7 +65,6 @@ InputManager::InputManager() : m_sensed_input(0), m_mode(BOOTSTRAP), // could not read config file so use defaults KeyboardDevice* default_device = new KeyboardDevice(); default_device->loadDefaults(); - m_device_manager->add( default_device ); something_new_to_write = true; }