2014-12-11 18:01:57 +00:00
/*
* This file is part of the Colobot : Gold Edition source code
* Copyright ( C ) 2001 - 2014 , Daniel Roux , EPSITEC SA & TerranovaTeam
* http : //epsiteс .ch; http://colobot.info; http://github.com/colobot
*
* 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 3 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 , see http : //gnu.org/licenses
*/
# include "app/input.h"
# include "common/logger.h"
2015-07-10 08:08:45 +00:00
# include "common/profile.h"
2014-12-11 18:01:57 +00:00
# include "common/restext.h"
# include "graphics/engine/engine.h"
# include "object/robotmain.h"
# include <sstream>
2015-07-10 08:25:31 +00:00
# include <boost/lexical_cast.hpp>
2014-12-11 18:01:57 +00:00
template < > CInput * CSingleton < CInput > : : m_instance = nullptr ;
CInput : : CInput ( )
{
m_kmodState = 0 ;
m_mousePos = Math : : Point ( ) ;
m_mouseButtonsState = 0 ;
2014-12-14 15:54:32 +00:00
for ( int i = 0 ; i < INPUT_SLOT_MAX ; i + + )
m_keyPresses [ i ] = false ;
2014-12-11 18:01:57 +00:00
m_joystickDeadzone = 0.2f ;
SetDefaultInputBindings ( ) ;
}
void CInput : : EventProcess ( Event & event )
{
if ( event . type = = EVENT_KEY_DOWN | |
event . type = = EVENT_KEY_UP )
{
// Use the occasion to update kmods
m_kmodState = event . kmodState ;
}
// Use the occasion to update mouse button state
if ( event . type = = EVENT_MOUSE_BUTTON_DOWN )
{
m_mouseButtonsState | = event . mouseButton . button ;
}
if ( event . type = = EVENT_MOUSE_BUTTON_UP )
{
m_mouseButtonsState & = ~ event . mouseButton . button ;
}
if ( event . type = = EVENT_KEY_DOWN | |
event . type = = EVENT_KEY_UP )
{
event . key . slot = FindBinding ( event . key . key ) ;
}
event . kmodState = m_kmodState ;
event . mousePos = m_mousePos ;
event . mouseButtonsState = m_mouseButtonsState ;
2014-12-14 15:54:32 +00:00
if ( event . type = = EVENT_KEY_DOWN | |
event . type = = EVENT_KEY_UP )
{
m_keyPresses [ event . key . slot ] = ( event . type = = EVENT_KEY_DOWN ) ;
}
2014-12-11 18:01:57 +00:00
/* Motion vector management */
2015-04-14 20:16:47 +00:00
if ( event . type = = EVENT_KEY_DOWN & & ! ( event . kmodState & KEY_MOD ( ALT ) ) )
2014-12-11 18:01:57 +00:00
{
if ( event . key . slot = = INPUT_SLOT_UP ) m_keyMotion . y = 1.0f ;
if ( event . key . slot = = INPUT_SLOT_DOWN ) m_keyMotion . y = - 1.0f ;
if ( event . key . slot = = INPUT_SLOT_LEFT ) m_keyMotion . x = - 1.0f ;
if ( event . key . slot = = INPUT_SLOT_RIGHT ) m_keyMotion . x = 1.0f ;
if ( event . key . slot = = INPUT_SLOT_GUP ) m_keyMotion . z = 1.0f ;
if ( event . key . slot = = INPUT_SLOT_GDOWN ) m_keyMotion . z = - 1.0f ;
}
else if ( event . type = = EVENT_KEY_UP )
{
if ( event . key . slot = = INPUT_SLOT_UP ) m_keyMotion . y = 0.0f ;
if ( event . key . slot = = INPUT_SLOT_DOWN ) m_keyMotion . y = 0.0f ;
if ( event . key . slot = = INPUT_SLOT_LEFT ) m_keyMotion . x = 0.0f ;
if ( event . key . slot = = INPUT_SLOT_RIGHT ) m_keyMotion . x = 0.0f ;
if ( event . key . slot = = INPUT_SLOT_GUP ) m_keyMotion . z = 0.0f ;
if ( event . key . slot = = INPUT_SLOT_GDOWN ) m_keyMotion . z = 0.0f ;
}
else if ( event . type = = EVENT_JOY_AXIS )
{
if ( event . joyAxis . axis = = GetJoyAxisBinding ( JOY_AXIS_SLOT_X ) . axis )
{
m_joyMotion . x = Math : : Neutral ( event . joyAxis . value / 32768.0f , m_joystickDeadzone ) ;
if ( GetJoyAxisBinding ( JOY_AXIS_SLOT_X ) . invert )
m_joyMotion . x * = - 1.0f ;
}
if ( event . joyAxis . axis = = GetJoyAxisBinding ( JOY_AXIS_SLOT_Y ) . axis )
{
m_joyMotion . y = Math : : Neutral ( event . joyAxis . value / 32768.0f , m_joystickDeadzone ) ;
if ( GetJoyAxisBinding ( JOY_AXIS_SLOT_Y ) . invert )
m_joyMotion . y * = - 1.0f ;
}
if ( event . joyAxis . axis = = GetJoyAxisBinding ( JOY_AXIS_SLOT_Z ) . axis )
{
m_joyMotion . z = Math : : Neutral ( event . joyAxis . value / 32768.0f , m_joystickDeadzone ) ;
if ( GetJoyAxisBinding ( JOY_AXIS_SLOT_Z ) . invert )
m_joyMotion . z * = - 1.0f ;
}
}
event . motionInput = Math : : Clamp ( m_joyMotion + m_keyMotion , Math : : Vector ( - 1.0f , - 1.0f , - 1.0f ) , Math : : Vector ( 1.0f , 1.0f , 1.0f ) ) ;
}
void CInput : : MouseMove ( Math : : IntPoint pos )
{
m_mousePos = Gfx : : CEngine : : GetInstancePointer ( ) - > WindowToInterfaceCoords ( pos ) ;
}
int CInput : : GetKmods ( ) const
{
return m_kmodState ;
}
bool CInput : : GetKmodState ( int kmod ) const
{
return ( m_kmodState & kmod ) ! = 0 ;
}
2014-12-14 15:54:32 +00:00
bool CInput : : GetKeyState ( InputSlot key ) const
2014-12-11 18:01:57 +00:00
{
2014-12-14 15:54:32 +00:00
return m_keyPresses [ key ] ;
2014-12-11 18:01:57 +00:00
}
bool CInput : : GetMouseButtonState ( int index ) const
{
return ( m_mouseButtonsState & ( 1 < < index ) ) ! = 0 ;
}
void CInput : : ResetKeyStates ( )
{
CLogger : : GetInstancePointer ( ) - > Trace ( " Reset key states \n " ) ;
m_kmodState = 0 ;
m_keyMotion = Math : : Vector ( 0.0f , 0.0f , 0.0f ) ;
m_joyMotion = Math : : Vector ( 0.0f , 0.0f , 0.0f ) ;
2014-12-14 15:54:32 +00:00
for ( int i = 0 ; i < INPUT_SLOT_MAX ; i + + )
m_keyPresses [ i ] = false ;
2014-12-11 18:01:57 +00:00
}
Math : : Point CInput : : GetMousePos ( ) const
{
return m_mousePos ;
}
void CInput : : SetDefaultInputBindings ( )
{
for ( int i = 0 ; i < INPUT_SLOT_MAX ; i + + )
{
m_inputBindings [ i ] . primary = m_inputBindings [ i ] . secondary = KEY_INVALID ;
}
for ( int i = 0 ; i < JOY_AXIS_SLOT_MAX ; i + + )
{
m_joyAxisBindings [ i ] . axis = AXIS_INVALID ;
m_joyAxisBindings [ i ] . invert = false ;
}
m_inputBindings [ INPUT_SLOT_LEFT ] . primary = KEY ( LEFT ) ;
m_inputBindings [ INPUT_SLOT_RIGHT ] . primary = KEY ( RIGHT ) ;
m_inputBindings [ INPUT_SLOT_UP ] . primary = KEY ( UP ) ;
m_inputBindings [ INPUT_SLOT_DOWN ] . primary = KEY ( DOWN ) ;
m_inputBindings [ INPUT_SLOT_LEFT ] . secondary = KEY ( a ) ;
m_inputBindings [ INPUT_SLOT_RIGHT ] . secondary = KEY ( d ) ;
m_inputBindings [ INPUT_SLOT_UP ] . secondary = KEY ( w ) ;
m_inputBindings [ INPUT_SLOT_DOWN ] . secondary = KEY ( s ) ;
m_inputBindings [ INPUT_SLOT_GUP ] . primary = VIRTUAL_KMOD ( SHIFT ) ;
m_inputBindings [ INPUT_SLOT_GDOWN ] . primary = VIRTUAL_KMOD ( CTRL ) ;
m_inputBindings [ INPUT_SLOT_CAMERA ] . primary = KEY ( SPACE ) ;
m_inputBindings [ INPUT_SLOT_DESEL ] . primary = KEY ( KP0 ) ;
m_inputBindings [ INPUT_SLOT_ACTION ] . primary = KEY ( RETURN ) ;
m_inputBindings [ INPUT_SLOT_ACTION ] . secondary = KEY ( e ) ;
m_inputBindings [ INPUT_SLOT_NEAR ] . primary = KEY ( KP_PLUS ) ;
m_inputBindings [ INPUT_SLOT_AWAY ] . primary = KEY ( KP_MINUS ) ;
m_inputBindings [ INPUT_SLOT_NEXT ] . primary = KEY ( TAB ) ;
m_inputBindings [ INPUT_SLOT_HUMAN ] . primary = KEY ( HOME ) ;
m_inputBindings [ INPUT_SLOT_QUIT ] . primary = KEY ( ESCAPE ) ;
m_inputBindings [ INPUT_SLOT_HELP ] . primary = KEY ( F1 ) ;
m_inputBindings [ INPUT_SLOT_PROG ] . primary = KEY ( F2 ) ;
m_inputBindings [ INPUT_SLOT_VISIT ] . primary = KEY ( KP_PERIOD ) ;
2014-12-14 16:05:28 +00:00
m_inputBindings [ INPUT_SLOT_SPEED05 ] . primary = KEY ( F3 ) ;
2014-12-11 18:01:57 +00:00
m_inputBindings [ INPUT_SLOT_SPEED10 ] . primary = KEY ( F4 ) ;
m_inputBindings [ INPUT_SLOT_SPEED15 ] . primary = KEY ( F5 ) ;
m_inputBindings [ INPUT_SLOT_SPEED20 ] . primary = KEY ( F6 ) ;
2014-12-14 16:05:28 +00:00
m_inputBindings [ INPUT_SLOT_SPEED30 ] . primary = KEY ( F7 ) ;
m_inputBindings [ INPUT_SLOT_SPEED40 ] . primary = KEY ( F8 ) ;
2014-12-14 15:54:32 +00:00
m_inputBindings [ INPUT_SLOT_CAMERA_UP ] . primary = KEY ( PAGEUP ) ;
m_inputBindings [ INPUT_SLOT_CAMERA_DOWN ] . primary = KEY ( PAGEDOWN ) ;
m_inputBindings [ INPUT_SLOT_PAUSE ] . primary = KEY ( PAUSE ) ;
m_inputBindings [ INPUT_SLOT_PAUSE ] . secondary = KEY ( p ) ;
2014-12-11 18:01:57 +00:00
m_joyAxisBindings [ JOY_AXIS_SLOT_X ] . axis = 0 ;
m_joyAxisBindings [ JOY_AXIS_SLOT_Y ] . axis = 1 ;
m_joyAxisBindings [ JOY_AXIS_SLOT_Z ] . axis = 2 ;
}
void CInput : : SetInputBinding ( InputSlot slot , InputBinding binding )
{
unsigned int index = static_cast < unsigned int > ( slot ) ;
m_inputBindings [ index ] = binding ;
}
const InputBinding & CInput : : GetInputBinding ( InputSlot slot )
{
unsigned int index = static_cast < unsigned int > ( slot ) ;
return m_inputBindings [ index ] ;
}
void CInput : : SetJoyAxisBinding ( JoyAxisSlot slot , JoyAxisBinding binding )
{
unsigned int index = static_cast < unsigned int > ( slot ) ;
m_joyAxisBindings [ index ] = binding ;
}
const JoyAxisBinding & CInput : : GetJoyAxisBinding ( JoyAxisSlot slot )
{
unsigned int index = static_cast < unsigned int > ( slot ) ;
return m_joyAxisBindings [ index ] ;
}
void CInput : : SetJoystickDeadzone ( float zone )
{
m_joystickDeadzone = zone ;
}
float CInput : : GetJoystickDeadzone ( )
{
return m_joystickDeadzone ;
}
InputSlot CInput : : FindBinding ( unsigned int key )
{
for ( int i = 0 ; i < INPUT_SLOT_MAX ; i + + )
{
InputSlot slot = static_cast < InputSlot > ( i ) ;
InputBinding b = GetInputBinding ( slot ) ;
if ( b . primary = = key | | b . secondary = = key )
return slot ;
}
return INPUT_SLOT_MAX ;
}
static std : : map < InputSlot , std : : string > keyTable =
{
{ INPUT_SLOT_LEFT , " left " } ,
{ INPUT_SLOT_RIGHT , " right " } ,
{ INPUT_SLOT_UP , " up " } ,
{ INPUT_SLOT_DOWN , " down " } ,
{ INPUT_SLOT_GUP , " gup " } ,
{ INPUT_SLOT_GDOWN , " gdown " } ,
{ INPUT_SLOT_CAMERA , " camera " } ,
{ INPUT_SLOT_DESEL , " desel " } ,
{ INPUT_SLOT_ACTION , " action " } ,
{ INPUT_SLOT_NEAR , " near " } ,
{ INPUT_SLOT_AWAY , " away " } ,
{ INPUT_SLOT_NEXT , " next " } ,
{ INPUT_SLOT_HUMAN , " human " } ,
{ INPUT_SLOT_QUIT , " quit " } ,
{ INPUT_SLOT_HELP , " help " } ,
{ INPUT_SLOT_PROG , " prog " } ,
{ INPUT_SLOT_VISIT , " visit " } ,
2014-12-14 16:05:28 +00:00
{ INPUT_SLOT_SPEED05 , " speed05 " } ,
2014-12-11 18:01:57 +00:00
{ INPUT_SLOT_SPEED10 , " speed10 " } ,
{ INPUT_SLOT_SPEED15 , " speed15 " } ,
2014-12-14 15:54:32 +00:00
{ INPUT_SLOT_SPEED20 , " speed20 " } ,
2014-12-14 16:05:28 +00:00
{ INPUT_SLOT_SPEED30 , " speed30 " } ,
{ INPUT_SLOT_SPEED40 , " speed40 " } ,
2014-12-14 15:54:32 +00:00
{ INPUT_SLOT_CAMERA_UP , " camup " } ,
{ INPUT_SLOT_CAMERA_DOWN , " camdown " } ,
2015-07-10 08:08:45 +00:00
{ INPUT_SLOT_PAUSE , " pause " } ,
2014-12-11 18:01:57 +00:00
} ;
2015-07-10 08:08:45 +00:00
void CInput : : SaveKeyBindings ( )
{
std : : stringstream key ;
for ( int i = 0 ; i < INPUT_SLOT_MAX ; i + + )
{
InputBinding b = GetInputBinding ( static_cast < InputSlot > ( i ) ) ;
key . clear ( ) ;
key . str ( " " ) ;
key < < b . primary < < " " < < b . secondary ;
CProfile : : GetInstancePointer ( ) - > SetStringProperty ( " Keybindings " , keyTable [ static_cast < InputSlot > ( i ) ] , key . str ( ) ) ;
}
2015-07-10 08:25:31 +00:00
for ( int i = 0 ; i < JOY_AXIS_SLOT_MAX ; i + + )
{
JoyAxisBinding b = GetJoyAxisBinding ( static_cast < JoyAxisSlot > ( i ) ) ;
CProfile : : GetInstancePointer ( ) - > SetIntProperty ( " Setup " , " JoystickAxisBinding " + boost : : lexical_cast < std : : string > ( i ) , b . axis ) ;
CProfile : : GetInstancePointer ( ) - > SetIntProperty ( " Setup " , " JoystickAxisInvert " + boost : : lexical_cast < std : : string > ( i ) , b . invert ) ;
}
CProfile : : GetInstancePointer ( ) - > SetFloatProperty ( " Setup " , " JoystickDeadzone " , GetJoystickDeadzone ( ) ) ;
2015-07-10 08:08:45 +00:00
}
void CInput : : LoadKeyBindings ( )
{
std : : stringstream skey ;
std : : string keys ;
for ( int i = 0 ; i < INPUT_SLOT_MAX ; i + + )
{
InputBinding b ;
if ( ! CProfile : : GetInstancePointer ( ) - > GetStringProperty ( " Keybindings " , keyTable [ static_cast < InputSlot > ( i ) ] , keys ) )
continue ;
skey . clear ( ) ;
skey . str ( keys ) ;
skey > > b . primary ;
skey > > b . secondary ;
SetInputBinding ( static_cast < InputSlot > ( i ) , b ) ;
}
2015-07-10 08:25:31 +00:00
for ( int i = 0 ; i < JOY_AXIS_SLOT_MAX ; i + + )
{
JoyAxisBinding b ;
if ( ! CProfile : : GetInstancePointer ( ) - > GetIntProperty ( " Setup " , " JoystickAxisBinding " + boost : : lexical_cast < std : : string > ( i ) , b . axis ) )
continue ;
int x = 0 ;
CProfile : : GetInstancePointer ( ) - > GetIntProperty ( " Setup " , " JoystickAxisInvert " + boost : : lexical_cast < std : : string > ( i ) , x ) ; // If doesn't exist, use default (0)
b . invert = ( x ! = 0 ) ;
SetJoyAxisBinding ( static_cast < JoyAxisSlot > ( i ) , b ) ;
}
float deadzone ;
if ( CProfile : : GetInstancePointer ( ) - > GetFloatProperty ( " Setup " , " JoystickDeadzone " , deadzone ) )
SetJoystickDeadzone ( deadzone ) ;
2015-07-10 08:08:45 +00:00
}
2014-12-11 18:01:57 +00:00
InputSlot CInput : : SearchKeyById ( std : : string id )
{
for ( auto & key : keyTable )
{
if ( id = = key . second )
{
return key . first ;
}
}
return INPUT_SLOT_MAX ;
}
std : : string CInput : : GetKeysString ( InputBinding b )
{
std : : ostringstream ss ;
if ( b . primary ! = KEY_INVALID )
{
std : : string iNameStr ;
if ( GetResource ( RES_KEY , b . primary , iNameStr ) )
{
ss < < iNameStr ;
if ( b . secondary ! = KEY_INVALID )
{
if ( GetResource ( RES_KEY , b . secondary , iNameStr ) )
{
std : : string textStr ;
GetResource ( RES_TEXT , RT_KEY_OR , textStr ) ;
ss < < textStr < < iNameStr ;
}
}
}
}
else
{
return " ? " ;
}
return ss . str ( ) ;
}
std : : string CInput : : GetKeysString ( InputSlot slot )
{
InputBinding b = GetInputBinding ( slot ) ;
return GetKeysString ( b ) ;
}