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
This commit is contained in:
rforder 2009-08-06 18:00:18 +00:00
parent 671fde19cf
commit 9ba0bd67d2
8 changed files with 447 additions and 85 deletions

View File

@ -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 \

View File

@ -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<PA_COUNT; n++) // Start at 0?
{
stream << " "
<< "<action "
<< "name=\"" << KartActionStrings[n] << "\" "
<< "id=\"" << m_bindings[n].id << "\" "
<< "event=\"" << m_bindings[n].type << "\" ";
// Only serialize the direction for stick motions
if (m_bindings[n].type == Input::IT_STICKMOTION)
{
stream << "direction=\"" << m_bindings[n].dir << "\" ";
}
stream << "/>\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 << "<keyboard>\n\n";
DeviceConfig::serialize(stream);
stream << "</keyboard>\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 << "<gamepad name =\"" << m_name.c_str() << "\">\n\n";
DeviceConfig::serialize(stream);
stream << "</gamepad>\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;
}

View File

@ -0,0 +1,96 @@
#ifndef DEVICE_CONFIG_HPP
#define DEVICE_CONFIG_HPP
#include <string>
#include "input/input.hpp"
#include <iostream>
#include <fstream>
#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

View File

@ -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();
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<m_gamepad_amount; n++)
for(int n=0; n<m_gamepad_configs.size(); n++)
{
std::cout << " (checking...) I remember that gamepad #" << n << " is named " << m_gamepads[n].m_name.c_str() << std::endl;
std::cout << " (checking...) I remember that gamepad configuration #" << n << " is named " << m_gamepad_configs[n].getName().c_str() << std::endl;
// FIXME - don't check only name, but also number of axes and buttons?
// Only assign device IDs to gamepads which have not yet been assigned a device ID
if((m_gamepads[n].m_name == name) && (m_gamepads[n].m_index == -1))
if(m_gamepad_configs[n].getName() == name)
{
std::cout << "--> 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,24 +315,26 @@ 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))
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))
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;
@ -355,6 +362,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 << "<input>\n\n";
for(unsigned int n=0; n<m_keyboard_amount; n++)
for(int n=0; n<m_keyboard_configs.size(); n++)
{
m_keyboards[n].serialize(configfile);
m_keyboard_configs[n].serialize(configfile);
}
for(unsigned int n=0; n<m_gamepad_amount; n++)
for(int n=0; n<m_gamepad_configs.size(); n++)
{
m_gamepads[n].serialize(configfile);
m_gamepad_configs[n].serialize(configfile);
}
configfile << "</input>\n";

View File

@ -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
@ -15,6 +16,8 @@ class DeviceManager
{
ptr_vector<KeyboardDevice, HOLD> m_keyboards;
ptr_vector<GamePadDevice, HOLD> m_gamepads;
ptr_vector<KeyboardConfig, HOLD> m_keyboard_configs;
ptr_vector<GamepadConfig, HOLD> m_gamepad_configs;
core::array<SJoystickInfo> 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);
};

View File

@ -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; n<PA_COUNT; n++)
@ -105,9 +107,16 @@ std::string InputDevice::getBindingAsString(const PlayerAction action) const
#pragma mark Keyboard
#endif
// -----------------------------------------------------------------------------
KeyboardDevice::KeyboardDevice(KeyboardConfig *configuration)
{
m_configuration = configuration;
m_type = DT_KEYBOARD;
}
// -----------------------------------------------------------------------------
KeyboardDevice::KeyboardDevice()
{
m_configuration = new KeyboardConfig();
m_type = DT_KEYBOARD;
}
// -----------------------------------------------------------------------------
@ -148,6 +157,7 @@ void KeyboardDevice::editBinding(PlayerAction action, int key_id)
/** checks if this key belongs to this belongs. if yes, sets action and returns true; otherwise returns false */
bool KeyboardDevice::hasBinding(const int key_id, PlayerAction* action /* out */) const
{
/*
for(int n=0; n<PA_COUNT; n++)
{
if(m_default_bindings[n].id == key_id)
@ -156,8 +166,8 @@ bool KeyboardDevice::hasBinding(const int key_id, PlayerAction* action /* out */
return true;
}
}// next device
return false;
*/
return m_configuration->getBinding(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<PA_COUNT; n++)
{
if(m_default_bindings[n].type == type && m_default_bindings[n].id == id)
{
if(m_default_bindings[n].dir == Input::AD_NEGATIVE && value < 0)
{
*action = (PlayerAction)n;
return true;
}
else if(m_default_bindings[n].dir == Input::AD_POSITIVE && value > 0)
{
*action = (PlayerAction)n;
return true;
}
}
}// next device
}
else if(type == Input::IT_STICKBUTTON)
{
// find corresponding action and return it
for(int n=0; n<PA_COUNT; n++)
{
if(m_default_bindings[n].type == type && m_default_bindings[n].id == id)
{
*action = (PlayerAction)n;
return true;
}
}// next device
}
return false;
return m_configuration->getBinding(type, id, value, action);
}
// -----------------------------------------------------------------------------
/** Destructor for GamePadDevice.

View File

@ -3,6 +3,7 @@
#include <string>
#include "input/input.hpp"
#include "config/device_config.hpp"
#include <iostream>
#include <fstream>
#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);

View File

@ -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;
}