From 059d9037a74d5510c2bc784dea051c50fde9f12c Mon Sep 17 00:00:00 2001 From: thebohemian Date: Wed, 3 Oct 2007 11:23:07 +0000 Subject: [PATCH] - 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 --- src/Makefile.am | 1 + src/gui/base_gui.cpp | 19 +++------ src/gui/base_gui.hpp | 3 ++ src/gui/menu_manager.cpp | 8 +++- src/gui/options.cpp | 10 +++-- src/gui/player_controls.cpp | 4 ++ src/gui/race_gui.cpp | 35 +++++----------- src/gui/race_gui.hpp | 20 ++------- src/inputmap.cpp | 74 +++++++++++++++++++++++++++++++++ src/inputmap.hpp | 52 +++++++++++++++++++++++ src/sdldrv.cpp | 82 +++++++++++++++++++++++++------------ src/sdldrv.hpp | 5 +++ 12 files changed, 227 insertions(+), 86 deletions(-) create mode 100644 src/inputmap.cpp create mode 100644 src/inputmap.hpp diff --git a/src/Makefile.am b/src/Makefile.am index 1e774cbaa..dacf2b803 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/gui/base_gui.cpp b/src/gui/base_gui.cpp index 89b9e45df..3e8f1826e 100644 --- a/src/gui/base_gui.cpp +++ b/src/gui/base_gui.cpp @@ -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) diff --git a/src/gui/base_gui.hpp b/src/gui/base_gui.hpp index e7aa5207f..c8d79992b 100644 --- a/src/gui/base_gui.hpp +++ b/src/gui/base_gui.hpp @@ -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: diff --git a/src/gui/menu_manager.cpp b/src/gui/menu_manager.cpp index 723c26991..fab724b11 100644 --- a/src/gui/menu_manager.cpp +++ b/src/gui/menu_manager.cpp @@ -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; diff --git a/src/gui/options.cpp b/src/gui/options.cpp index 3b1f68ab5..70e9047c2 100644 --- a/src/gui/options.cpp +++ b/src/gui/options.cpp @@ -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 to go back"), GUI_SML, WTOK_BACK); diff --git a/src/gui/player_controls.cpp b/src/gui/player_controls.cpp index c20f67314..20c9dbcc8 100644 --- a/src/gui/player_controls.cpp +++ b/src/gui/player_controls.cpp @@ -24,6 +24,7 @@ #include "user_config.hpp" #include "menu_manager.hpp" #include "translation.hpp" +#include "sdldrv.hpp" #include @@ -88,6 +89,8 @@ void PlayerControls::select() } m_edit_action = static_cast(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. diff --git a/src/gui/race_gui.cpp b/src/gui/race_gui.cpp index 8032e7c34..0d021eb22 100644 --- a/src/gui/race_gui.cpp +++ b/src/gui/race_gui.cpp @@ -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;id0clear(); // 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 diff --git a/src/gui/race_gui.hpp b/src/gui/race_gui.hpp index d7f3d241c..996f7c556 100644 --- a/src/gui/race_gui.hpp +++ b/src/gui/race_gui.hpp @@ -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 (); diff --git a/src/inputmap.cpp b/src/inputmap.cpp new file mode 100644 index 000000000..a08ef7e30 --- /dev/null +++ b/src/inputmap.cpp @@ -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 + +#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::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); +} + diff --git a/src/inputmap.hpp b/src/inputmap.hpp new file mode 100644 index 000000000..3e7f5e55e --- /dev/null +++ b/src/inputmap.hpp @@ -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 +#include "player.hpp" + +class Playerkart; + +class InputMap +{ + typedef std::pair 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 inputMap; + +}; + +#endif diff --git a/src/sdldrv.cpp b/src/sdldrv.cpp index 267ad7e36..dc39ac701 100755 --- a/src/sdldrv.cpp +++ b/src/sdldrv.cpp @@ -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); + } diff --git a/src/sdldrv.hpp b/src/sdldrv.hpp index 81186e595..2c22eb978 100755 --- a/src/sdldrv.hpp +++ b/src/sdldrv.hpp @@ -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();