- separate input map implementation

- make mouse axes work like analog axes
 - enable display menu for non-Win32 platforms


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@1272 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
thebohemian 2007-10-03 11:23:07 +00:00
parent 9ea37bf14f
commit 059d9037a7
12 changed files with 227 additions and 86 deletions

View File

@ -38,6 +38,7 @@ supertuxkart_SOURCES = main.cpp \
music_ogg.cpp music_ogg.hpp \
sfx_openal.cpp sfx_openal.hpp \
utils.cpp utils.hpp \
inputmap.cpp inputmap.hpp \
isect.cpp isect.hpp \
track.cpp track.hpp \
herring.cpp herring.hpp \

View File

@ -31,19 +31,6 @@ void BaseGUI::input(InputType type, int id0, int id1, int id2, int value)
case IT_KEYBOARD:
inputKeyboard(id0, value);
break;
case IT_MOUSEMOTION:
widgetSet->pulse(widgetSet->point(m_menu_id, id0, id1), 1.2f);
#ifdef ALT_MOUSE_HANDLING
if (id0 == 1 && value)
if (id1 == AD_NEGATIVE)
inputKeyboard(SDLK_UP, 1);
else
inputKeyboard(SDLK_DOWN, 1);
#endif
break;
case IT_MOUSEBUTTON:
if (!value) // Act on button release only.
switch (id0)
@ -131,6 +118,12 @@ void BaseGUI::inputKeyboard(int key, int pressed)
break;
} // switch
} // inputKeyboard
//-----------------------------------------------------------------------------
void
BaseGUI::inputPointer(int x, int y)
{
widgetSet->pulse(widgetSet->point(m_menu_id, x, y), 1.2f);
}
//-----------------------------------------------------------------------------
void BaseGUI::update(float dt)

View File

@ -33,6 +33,9 @@ public:
virtual void input(InputType type, int id0, int id1, int id2, int value);
virtual void inputKeyboard(int key, int pressed);
void inputPointer(int x, int y);
void TimeToString(const float time, char *s);
protected:

View File

@ -46,6 +46,7 @@
#include "credits_menu.hpp"
#include "grand_prix_select.hpp"
#include "sound_manager.hpp"
#include "sdldrv.hpp"
MenuManager* menu_manager= new MenuManager();
@ -93,7 +94,11 @@ void MenuManager::update()
if (m_handled_size != m_menu_stack.size())
{
if(m_current_menu==m_RaceGUI) m_RaceGUI=0;
if(m_current_menu==m_RaceGUI)
{
m_RaceGUI = 0;
drv_showPointer();
}
delete m_current_menu;
m_current_menu= NULL;
@ -132,6 +137,7 @@ void MenuManager::update()
m_current_menu= new NumPlayers();
break;
case MENUID_RACE:
drv_hidePointer();
m_current_menu = new RaceGUI();
m_RaceGUI = m_current_menu;
break;

View File

@ -37,14 +37,16 @@ Options::Options()
widgetSet -> space(m_menu_id);
widgetSet -> label(m_menu_id, _("Options"), GUI_LRG, GUI_ALL, 0, 0);
widgetSet -> start(m_menu_id, _("Player Config"), GUI_MED, WTOK_CONTROLS);
#ifndef WIN32
// Don't display the fullscreen menu when called from within the race.
// (Windows only)
// The fullscreen mode will reload all textures, reload the models,
// ... basically creating a big mess!! (and all of this only thanks
// to windows, who discards all textures, ...)
if(!menu_manager->isSomewhereOnStack(MENUID_RACE))
{
widgetSet -> state(m_menu_id, _("Display"), GUI_MED, WTOK_DISPLAY);
}
widgetSet -> state(m_menu_id, _("Display"), GUI_MED, WTOK_DISPLAY);
#endif
widgetSet -> state(m_menu_id, _("Sound"), GUI_MED, WTOK_SOUND);
widgetSet -> space(m_menu_id);
widgetSet -> state(m_menu_id, _("Press <ESC> to go back"), GUI_SML, WTOK_BACK);

View File

@ -24,6 +24,7 @@
#include "user_config.hpp"
#include "menu_manager.hpp"
#include "translation.hpp"
#include "sdldrv.hpp"
#include <string>
@ -88,6 +89,8 @@ void PlayerControls::select()
}
m_edit_action = static_cast<KartActions>(MENU_CHOICE);
m_grab_input = true;
drv_hidePointer();
widgetSet->set_label(m_grab_id, _("Press key"));
} // select
@ -138,6 +141,7 @@ void PlayerControls::input(InputType type, int id0, int id1, int id2, int value)
// ------------------------------
else
{
drv_showPointer();
m_grab_input = false;
// Do not accept pressing ESC as input.

View File

@ -29,8 +29,9 @@
#include "sdldrv.hpp"
#include "translation.hpp"
#include "font.hpp"
#include "inputmap.hpp"
RaceGUI::RaceGUI(): m_time_left(0.0)
RaceGUI::RaceGUI(): m_input_map (new InputMap()), m_time_left(0.0)
{
if(user_config->m_fullscreen)
{
@ -39,7 +40,7 @@ RaceGUI::RaceGUI(): m_time_left(0.0)
if(!user_config->m_profile)
{
UpdateKeyboardMappings();
updateInputMappings();
} // if !user_config->m_profile
// FIXME: translation problem
@ -74,6 +75,8 @@ RaceGUI::RaceGUI(): m_time_left(0.0)
//-----------------------------------------------------------------------------
RaceGUI::~RaceGUI()
{
delete m_input_map;
if(user_config->m_fullscreen)
{
SDL_ShowCursor(SDL_ENABLE);
@ -82,15 +85,9 @@ RaceGUI::~RaceGUI()
} // ~Racegui
//-----------------------------------------------------------------------------
void RaceGUI::UpdateKeyboardMappings()
void RaceGUI::updateInputMappings()
{
// Clear all entries.
for(int type = 0;type< (int) IT_LAST+1;type++)
for(int id0=0;id0<MAX_ID0;id0++)
for(int id1=0;id1<MAX_ID1;id1++)
for(int id2=0;id2<MAX_ID2;id2++)
m_input_map[type][id0][id1][id2].kart = NULL;
m_input_map->clear();
// Defines the mappings for player keys to kart and action
// To avoid looping over all players to find out what
@ -104,29 +101,19 @@ void RaceGUI::UpdateKeyboardMappings()
PlayerKart* kart = world->getPlayerKart(i);
for(int ka=(int)KC_FIRST; ka < (int)KC_LAST+1; ka++)
putEntry(kart, (KartActions) ka);
m_input_map->putEntry(kart, (KartActions) ka);
}
} // UpdateKeyControl
//-----------------------------------------------------------------------------
void RaceGUI::putEntry(PlayerKart *kart, KartActions kc)
{
Player *p = kart->getPlayer();
const Input *I = p->getInput(kc);
m_input_map[I->type][I->id0][I->id1][I->id2].kart = kart;
m_input_map[I->type][I->id0][I->id1][I->id2].action = kc;
}
//-----------------------------------------------------------------------------
bool RaceGUI::handleInput(InputType type, int id0, int id1, int id2, int value)
{
PlayerKart *k = m_input_map[type][id0][id1][id2].kart;
InputMap::Entry *e = m_input_map->getEntry(type, id0, id1, id2);
if (k)
if (e)
{
k->action(m_input_map[type][id0][id1][id2].action, value);
e->kart->action(e->action, value);
return true;
}
else

View File

@ -31,25 +31,11 @@
#include "player.hpp"
#include "world.hpp"
// TODO: Fix this.
#define MAX_ID0 512
#define MAX_ID1 16
#define MAX_ID2 2
typedef struct
{
PlayerKart *kart;
KartActions action;
}
Entry;
class InputMap;
class RaceSetup;
class RaceGUI: public BaseGUI
{
// A mapping for the assigned keys (like fire, ...) to
// the kart which is using them
Entry m_input_map[IT_LAST+1][MAX_ID0][MAX_ID1][MAX_ID2];
class TimedMessage
{
@ -86,6 +72,7 @@ public:
int red=255, int green=0, int blue=255);
private:
InputMap *m_input_map;
ulClock m_fps_timer;
int m_fps_counter;
char m_fps_string[10];
@ -108,8 +95,7 @@ private:
void drawAllMessages (Kart* player_kart,
int offset_x, int offset_y,
float ratio_x, float ratio_y );
void UpdateKeyboardMappings();
void putEntry(PlayerKart *kart, KartActions ka);
void updateInputMappings();
bool handleInput(InputType type, int id0, int id1, int id2, int value);
void inputKeyboard(int key, int pressed);
void drawPlayerIcons ();

74
src/inputmap.cpp Normal file
View File

@ -0,0 +1,74 @@
// $Id: inputmap.cpp 1259 2007-09-24 12:28:19Z thebohemian $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2007 Robert Schuster
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <map>
#include "player.hpp"
#include "player_kart.hpp"
#include "inputmap.hpp"
using namespace std;
void
InputMap::putEntry(PlayerKart *kart, KartActions kc)
{
Player *p = kart->getPlayer();
const Input *i = p->getInput(kc);
Entry *e = new Entry();
e->kart = kart;
e->action = kc;
inputMap[key(i->type, i->id0, i->id1, i->id2)] = e;
}
InputMap::Entry *
InputMap::getEntry(InputType it, int id0, int id1, int id2)
{
return inputMap[key(it, id0, id1, id2)];
}
void
InputMap::clear()
{
for (map<Key, Entry *>::iterator i = inputMap.begin();
i != inputMap.end(); i++)
{
delete i->second;
}
inputMap.clear();
}
InputMap::Key
InputMap::key(InputType it, int id0, int id1, int id2)
{
/*
* A short reminder on the bit distribution and their usage:
* it gets 8 bits (InputType)
* id1 gets 16 bits (button, hat or axis number)
* id2 gets 8 bits (direction bit)
* id0 gets 32 bits (That is because id0 can be the keyboard key ids and
* those are unicode and unicode 4.0 is 32 bit)
*
* Assumption: int is (at least) 32 bit
*/
return Key(it << 24 | id1 << 8 | id2, id0);
}

52
src/inputmap.hpp Normal file
View File

@ -0,0 +1,52 @@
// $Id: inputmap.hpp 1259 2007-09-24 12:28:19Z thebohemian $
//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2007 Robert Schuster
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_INPUTMAP_H
#define HEADER_INPUTMAP_H
#include <map>
#include "player.hpp"
class Playerkart;
class InputMap
{
typedef std::pair<int, int> Key;
public:
typedef struct
{
PlayerKart *kart;
KartActions action;
} Entry;
void clear();
void putEntry(PlayerKart *, KartActions);
Entry *getEntry(InputType, int, int, int);
private:
Key key(InputType, int, int, int);
std::map<Key, Entry *> inputMap;
};
#endif

View File

@ -39,9 +39,15 @@ SDL_Surface *mainSurface;
long flags;
SDL_Joystick **sticks;
bool pointerVisible = true;
#define DEADZONE_MOUSE 1
#define DEADZONE_JOYSTICK 1000
#define MULTIPLIER_MOUSE 750
int mouseValX = 0;
int mouseValY = 0;
//-----------------------------------------------------------------------------
void drv_init()
{
@ -67,6 +73,20 @@ void drv_init()
ssgInit () ;
}
//-----------------------------------------------------------------------------
void
drv_showPointer()
{
pointerVisible = true;
SDL_ShowCursor(SDL_ENABLE);
}
//-----------------------------------------------------------------------------
void
drv_hidePointer()
{
pointerVisible = false;
SDL_ShowCursor(SDL_DISABLE);
}
//-----------------------------------------------------------------------------
void drv_toggleFullscreen(int resetTextures)
{
@ -79,10 +99,10 @@ void drv_toggleFullscreen(int resetTextures)
flags |= SDL_FULLSCREEN;
if(menu_manager->isSomewhereOnStack(MENUID_RACE))
SDL_ShowCursor(SDL_DISABLE);
drv_showPointer();
}
else if(menu_manager->isSomewhereOnStack(MENUID_RACE))
SDL_ShowCursor(SDL_ENABLE);
drv_hidePointer();
SDL_FreeSurface(mainSurface);
mainSurface = SDL_SetVideoMode(user_config->m_width, user_config->m_height, 0, flags);
@ -168,32 +188,28 @@ void drv_loop()
break;
case SDL_MOUSEMOTION:
input(IT_MOUSEMOTION, ev.motion.x, mainSurface->h - ev.motion.y, 0, 0);
#ifdef ALT_MOUSE_HANDLING
// This probably needs better handling
if (ev.motion.xrel < -DEADZONE_MOUSE)
input(IT_MOUSEMOTION, 0, AD_NEGATIVE, 0, 1);
else if(ev.motion.xrel > DEADZONE_MOUSE)
input(IT_MOUSEMOTION, 0, AD_POSITIVE, 0, 1);
else
{
input(IT_MOUSEMOTION, 0, AD_NEGATIVE, 0, 0);
input(IT_MOUSEMOTION, 0, AD_POSITIVE, 0, 0);
}
if (ev.motion.yrel < -DEADZONE_MOUSE)
input(IT_MOUSEMOTION, 1, AD_NEGATIVE, 0, 1);
else if(ev.motion.yrel > DEADZONE_MOUSE)
input(IT_MOUSEMOTION, 1, AD_POSITIVE, 0, 1);
else
{
input(IT_MOUSEMOTION, 1, AD_NEGATIVE, 0, 0);
input(IT_MOUSEMOTION, 1, AD_POSITIVE, 0, 0);
}
#endif
break;
if (pointerVisible)
{
BaseGUI* menu= menu_manager->getCurrentMenu();
if (menu != NULL)
menu->inputPointer(ev.motion.x, mainSurface->h - ev.motion.y);
// Reset parameters for relative mouse handling to make sure we are
// in a valid state when returning to relative mouse mode
mouseValX = mouseValY = 0;
}
else
{
mouseValX = std::max(-32768,
std::min(32768, mouseValX
+ ev.motion.xrel
* MULTIPLIER_MOUSE));
mouseValY = std::max(-32768,
std::min(32768, mouseValY
+ ev.motion.yrel
* MULTIPLIER_MOUSE));
}
break;
case SDL_MOUSEBUTTONUP:
input(IT_MOUSEBUTTON, ev.button.button, 0, 0, 0);
break;
@ -224,4 +240,16 @@ void drv_loop()
break;
} // switch
} // while (SDL_PollEvent())
// Makes mouse behave like an analog axis.
if (mouseValX <= DEADZONE_MOUSE)
input(IT_MOUSEMOTION, 0, AD_NEGATIVE, 0, -mouseValX);
else if (mouseValX >= DEADZONE_MOUSE)
input(IT_MOUSEMOTION, 0, AD_POSITIVE, 0, mouseValX);
if (mouseValY <= DEADZONE_MOUSE)
input(IT_MOUSEMOTION, 1, AD_NEGATIVE, 0, -mouseValY);
else if (mouseValY >= DEADZONE_MOUSE)
input(IT_MOUSEMOTION, 1, AD_POSITIVE, 0, mouseValY);
}

View File

@ -20,9 +20,14 @@
#ifndef HEADER_SDLDRV_H
#define HEADER_SDLDRV_H
enum MouseState { INITIAL, MOVED, RESET_NEEDED };
void drv_init();
void drv_deinit();
void drv_showPointer();
void drv_hidePointer();
void drv_toggleFullscreen(int resetTextures=1);
void drv_loop();