Much cleanup and documentation in input code, which was done on the way of fixing a bug that dealt with multiple and/or custom keyboard configs and menu navigation

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@4355 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2009-12-27 19:12:44 +00:00
parent 2caccb8c6e
commit df422703ac
7 changed files with 102 additions and 59 deletions

View File

@ -51,7 +51,7 @@ void DeviceConfig::setBinding ( const PlayerAction action,
bool DeviceConfig::getAction ( Input::InputType type,
const int id,
const int value,
PlayerAction* action )
PlayerAction* action /* out */ )
{
bool success = false;
int n;

View File

@ -53,7 +53,7 @@ public:
bool getAction (Input::InputType type,
const int id,
const int value,
PlayerAction* action);
PlayerAction* action /* out */);
KeyBinding getBinding (int i) {return m_bindings[i];}
bool hasBindingFor(const int buttonID) const;

View File

@ -172,23 +172,29 @@ void DeviceManager::addGamepad(GamePadDevice* d)
}
// -----------------------------------------------------------------------------
InputDevice* DeviceManager::mapKeyboardInput( int deviceID,
int btnID,
ActivePlayer **player,
PlayerAction *action )
InputDevice* DeviceManager::mapKeyboardInput( int btnID,
ActivePlayer **player /* out */,
PlayerAction *action /* out */ )
{
const int keyboard_amount = m_keyboards.size();
//std::cout << "mapKeyboardInput " << btnID << " to " << keyboard_amount << " keyboards\n";
for (int n=0; n<keyboard_amount; n++)
{
KeyboardDevice *keyboard = m_keyboards.get(n);
if (keyboard->hasBinding(btnID, action))
{
//std::cout << " binding found in keyboard #" << (n+1) << "; action is " << KartActionStrings[*action] << "\n";
if (m_assign_mode == NO_ASSIGN) // Don't set the player in NO_ASSIGN mode
{
*player = NULL;
}
else *player = keyboard->m_player;
else
{
*player = keyboard->m_player;
}
return keyboard;
}
}
@ -202,8 +208,8 @@ InputDevice *DeviceManager::mapGamepadInput( Input::InputType type,
int btnID,
int axisDir,
int value,
ActivePlayer **player,
PlayerAction *action )
ActivePlayer **player /* out */,
PlayerAction *action /* out */)
{
GamePadDevice *gPad = getGamePadFromIrrID(deviceID);
@ -227,8 +233,6 @@ InputDevice *DeviceManager::mapGamepadInput( Input::InputType type,
}
//-----------------------------------------------------------------------------
// Formerly mapInputToPlayerAndAction(), broken down to be more readable
bool DeviceManager::translateInput( Input::InputType type,
int deviceID,
int btnID,
@ -243,7 +247,7 @@ bool DeviceManager::translateInput( Input::InputType type,
switch (type)
{
case Input::IT_KEYBOARD:
device = mapKeyboardInput(deviceID, btnID, player, action);
device = mapKeyboardInput(btnID, player, action);
break;
case Input::IT_STICKBUTTON:
case Input::IT_STICKMOTION:
@ -253,6 +257,12 @@ bool DeviceManager::translateInput( Input::InputType type,
break;
};
/*
if (device != NULL)
{
std::cout << " binding found; action is " << KartActionStrings[*action] << "\n";
}*/
// Return true if input was successfully translated to an action and player
if (device != NULL && abs(value) > Input::MAX_VALUE/2)
{

View File

@ -7,11 +7,23 @@
enum PlayerAssignMode
{
NO_ASSIGN, // react to all devices
DETECT_NEW, // notify the manager when an inactive device is being asked to activate with fire
ASSIGN // only react to assigned devices
NO_ASSIGN, //!< react to all devices
DETECT_NEW, //!< notify the manager when an inactive device is being asked to activate with fire
ASSIGN //!< only react to assigned devices
};
/**
* This class holds the list of all known devices (ands their configurations), as well as the list
* of currently plugged (used) devices. It thus takes care of finding to which device any given
* input belongs, and what action each keypress is bound to, if any (and, since each device is associated
* to a player, it also finds which player triggered this action)
* These input mapping capabilities should *only* be used through the InputManager, not directly.
*
* The device manager starts in "no-assign" mode, which means no input configuration is associated
* to any player. So all devices will react. This is used in menus before player set-up is done.
* Switching back to no-assign mode will also clear anything in devices that was associated with
* players in assign mode.
*/
class DeviceManager
{
private:
@ -24,67 +36,71 @@ private:
InputDevice* m_latest_used_device;
PlayerAssignMode m_assign_mode;
// Helper functions, only used internally
/**
* Helper method, only used internally. Takes care of analyzing gamepad input.
*
* \param[out] player Which player this input belongs to (only set in ASSIGN mode)
* \param[out] action Which action is related to this input trigger
* \return The device to which this input belongs
*/
InputDevice *mapGamepadInput ( Input::InputType type,
int deviceID,
int btnID,
int axisDir,
int value,
ActivePlayer **player,
PlayerAction *action );
ActivePlayer **player /* out */,
PlayerAction *action /* out */);
InputDevice *mapKeyboardInput ( int deviceID,
int btnID,
ActivePlayer **player,
PlayerAction *action );
/**
* Helper method, only used internally. Takes care of analyzing keyboard input.
*
* \param[out] player Which player this input belongs to (only set in ASSIGN mode)
* \param[out] action Which action is related to this input trigger
* \return The device to which this input belongs
*/
InputDevice *mapKeyboardInput ( int btnID,
ActivePlayer **player /* out */,
PlayerAction *action /* out */);
bool deserialize();
void shutdown();
public:
/**
* The device manager starts in "no-assign" mode, which means no input configuration is associated
* to any player. So all devices will react. This is used in menus before player set-up is done.
* Switching back to no-assign mode will also clear anything in devices that was associated with
* players in assign mode.
*/
DeviceManager();
// ---- Assign mode ----
PlayerAssignMode getAssignMode() const { return m_assign_mode; }
void setAssignMode(const PlayerAssignMode assignMode);
// ---- Gamepads ----
void addGamepad(GamePadDevice* d);
int getGamePadAmount() const { return m_gamepads.size(); }
int getGamePadConfigAmount() const { return m_gamepad_configs.size(); }
GamePadDevice* getGamePad(const int i) { return m_gamepads.get(i); }
GamepadConfig* getGamepadConfig(const int i) { return m_gamepad_configs.get(i); }
void clearGamepads() { m_gamepads.clearAndDeleteAll(); }
GamePadDevice* getGamePadFromIrrID(const int i);
void clearGamepads() { m_gamepads.clearAndDeleteAll(); }
/** Returns the keyboard that has a binding for this button, or NULL if none */
bool getConfigForGamepad(const int sdl_id, GamepadConfig **config);
// ---- Keyboard(s) ----
void addKeyboard(KeyboardDevice* d);
int getKeyboardConfigAmount() const { return m_keyboard_configs.size(); }
KeyboardDevice* getKeyboard(const int i) { return m_keyboards.get(i); }
KeyboardConfig* getKeyboardConfig(const int i) { return m_keyboard_configs.get(i); }
void clearKeyboard() { m_keyboards.clearAndDeleteAll(); }
PlayerAssignMode playerAssignMode() const { return m_assign_mode; }
/** Returns the keyboard that has a binding for this button, or NULL if none */
void clearKeyboard() { m_keyboards.clearAndDeleteAll(); }
KeyboardDevice* getKeyboardFromBtnID(const int btnID);
PlayerAssignMode getAssignMode() { return m_assign_mode; }
GamePadDevice* getGamePadFromIrrID(const int i);
InputDevice* getLatestUsedDevice();
void setAssignMode(const PlayerAssignMode assignMode);
bool getConfigForGamepad(const int sdl_id, GamepadConfig **config);
/** Given some input, finds to which device it belongs and, using the corresponding device object,
* maps this input to the corresponding player and game action. returns false if player/action could not be set.
* Special case : can return true but set action to PA_FIRST if the input was used but is not associated to an
* action and a player
*/
bool translateInput( Input::InputType type,
int deviceID,
int btnID,
@ -93,7 +109,7 @@ public:
ActivePlayer** player /* out */,
PlayerAction* action /* out */ );
/* returns whether a new gamepad was detected */
InputDevice* getLatestUsedDevice();
bool initialize();
void serialize();
};

View File

@ -44,7 +44,7 @@ KeyboardDevice::KeyboardDevice()
}
// -----------------------------------------------------------------------------
bool KeyboardDevice::hasBinding(const int id, PlayerAction* action)
bool KeyboardDevice::hasBinding(const int id, PlayerAction* action /* out */)
{
return m_configuration->getAction(Input::IT_KEYBOARD, id, 0, action);
}

View File

@ -44,11 +44,19 @@ public:
class KeyboardDevice : public InputDevice
{
public:
bool hasBinding(const int id, PlayerAction* action);
KeyboardDevice();
KeyboardDevice(KeyboardConfig *configuration);
/** checks if this key belongs to this belongs. if yes, sets action and returns true; otherwise returns false */
/**
* Checks if this key belongs to this device. if yes, sets action and returns true; otherwise returns false
*
* \param id ID of the key that was pressed
* \param[out] action The action associated to this input (only check this value if method returned true)
*/
bool hasBinding(const int id, PlayerAction* action);
};
class GamePadDevice : public InputDevice
@ -63,17 +71,22 @@ public:
int m_axis_count;
int m_button_count;
/** checks if this key belongs to this belongs. if yes, sets action and returns true; otherwise returns false.
The 'player' id passed is simply to know where to send 'axis reset's when necessary*/
bool hasBinding(Input::InputType type, const int id, const int value, ActivePlayer* player, PlayerAction* action);
GamePadDevice(const int irrIndex, const std::string name, const int axis_number, const int btnAmount, GamepadConfig *configuration);
~GamePadDevice();
bool isButtonPressed(const int i);
void setButtonPressed(const int i, bool isButtonPressed);
~GamePadDevice();
/**
* Checks if this key belongs to this device. if yes, sets action and returns true; otherwise returns false.
*
* \param player Only passed to know where to send 'axis reset's when necessary
* \param id ID of the key that was pressed or of the axis that was triggered (depending on
* the value of the 'type' parameter)
* \param[out] action The action associated to this input (only check this value if method returned true)
*/
bool hasBinding(Input::InputType type, const int id, const int value, ActivePlayer* player, PlayerAction* action);
};

View File

@ -228,7 +228,7 @@ void InputManager::inputSensing(Input::InputType type, int deviceID, int btnID,
int InputManager::getPlayerKeyboardID() const
{
// In no-assign mode, just return the GUI player ID (devices not assigned yet)
if (m_device_manager->playerAssignMode() == NO_ASSIGN) return GUI_PLAYER_ID;
if (m_device_manager->getAssignMode() == NO_ASSIGN) return GUI_PLAYER_ID;
// Otherwise, after devices are assigned, we can check the ID
// FIXME: don't hardcode keyboard 0, there may be multiple keyboard configs
@ -262,8 +262,8 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int btnID,
// in menus, some keyboard keys are standard (before each player selected his device)
// FIXME: should enter always work to accept for a player using keyboard?
if (StateManager::get()->getGameState() != GUIEngine::GAME && type == Input::IT_KEYBOARD && m_mode == MENU &&
m_device_manager->playerAssignMode() == NO_ASSIGN)
if (!action_found && StateManager::get()->getGameState() != GUIEngine::GAME && type == Input::IT_KEYBOARD &&
m_mode == MENU && m_device_manager->getAssignMode() == NO_ASSIGN)
{
action = PA_FIRST;
@ -273,7 +273,10 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int btnID,
else if (btnID == KEY_RIGHT) action = PA_RIGHT;
else if (btnID == KEY_SPACE) action = PA_FIRE;
if(btnID == KEY_RETURN && GUIEngine::ModalDialog::isADialogActive()) GUIEngine::ModalDialog::onEnterPressed();
if (btnID == KEY_RETURN && GUIEngine::ModalDialog::isADialogActive())
{
GUIEngine::ModalDialog::onEnterPressed();
}
if (action != PA_FIRST)
{
@ -364,6 +367,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int btnID,
// ... when in menus
else
{
// reset timer when released
if (abs(value) == 0 && (/*type == Input::IT_KEYBOARD ||*/ type == Input::IT_STICKBUTTON))
{
@ -390,7 +394,7 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID, int btnID,
}
}
}
else if(type == Input::IT_KEYBOARD)
else if (type == Input::IT_KEYBOARD)
{
// keyboard press not handled by device manager / bindings. Check static bindings...
handleStaticAction( btnID, value );
@ -557,7 +561,7 @@ EventPropagation InputManager::input(const SEvent& event)
#endif
// block events in all modes but initial menus (except in text boxes to allow typing, and except in modal dialogs in-game)
if (getDeviceList()->playerAssignMode() != NO_ASSIGN && !GUIEngine::isWithinATextBox() &&
if (getDeviceList()->getAssignMode() != NO_ASSIGN && !GUIEngine::isWithinATextBox() &&
(!GUIEngine::ModalDialog::isADialogActive() && StateManager::get()->getGameState() == GUIEngine::GAME))
{
return EVENT_BLOCK;