2009-05-08 13:28:41 +00:00
/*
* OpenClonk , http : //www.openclonk.org
*
2013-12-17 20:01:09 +00:00
* Copyright ( c ) 2005 - 2009 , RedWolf Design GmbH , http : //www.clonk.de/
2016-04-03 18:18:29 +00:00
* Copyright ( c ) 2009 - 2016 , The OpenClonk Team and contributors
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* Distributed under the terms of the ISC license ; see accompanying file
* " COPYING " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* " Clonk " is a registered trademark of Matthes Bender , used with permission .
* See accompanying file " TRADEMARK " for details .
2009-05-08 13:28:41 +00:00
*
2013-12-17 20:01:09 +00:00
* To redistribute this file separately , substitute the full license texts
* for the above references .
2009-05-08 13:28:41 +00:00
*/
// Keyboard input mapping to engine functions
2016-04-03 18:07:56 +00:00
# include "C4Include.h"
# include "gui/C4KeyboardInput.h"
2009-05-08 13:28:41 +00:00
2018-01-17 23:40:39 +00:00
# include "gui/C4MouseControl.h"
2016-04-03 18:07:56 +00:00
# include "c4group/C4Components.h"
# include "platform/C4Window.h"
2009-05-08 13:28:41 +00:00
2016-02-19 15:16:33 +00:00
# include <unordered_map>
2009-10-25 23:09:34 +00:00
2016-02-13 22:28:00 +00:00
# ifdef HAVE_SDL
2012-03-23 21:53:56 +00:00
# include <SDL.h>
2009-05-08 13:28:41 +00:00
# endif
2016-08-20 21:15:53 +00:00
# ifdef USE_SDL_MAINLOOP
// Required for KeycodeToString translation table.
# include "platform/C4App.h"
# endif
2009-05-08 13:28:41 +00:00
/* ----------------- Key maps ------------------ */
struct C4KeyShiftMapEntry
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4KeyShiftState eShift ;
const char * szName ;
2010-03-28 18:58:01 +00:00
} ;
2009-05-08 13:28:41 +00:00
2010-03-28 18:58:01 +00:00
const C4KeyShiftMapEntry KeyShiftMap [ ] =
{
2009-05-08 13:28:41 +00:00
{ KEYS_Alt , " Alt " } ,
{ KEYS_Control , " Ctrl " } ,
{ KEYS_Shift , " Shift " } ,
2016-11-02 23:58:02 +00:00
{ KEYS_Undefined , nullptr }
2010-03-28 18:58:01 +00:00
} ;
2009-05-08 13:28:41 +00:00
C4KeyShiftState C4KeyCodeEx : : String2KeyShift ( const StdStrBuf & sName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// query map
const C4KeyShiftMapEntry * pCheck = KeyShiftMap ;
while ( pCheck - > szName )
2010-03-28 18:58:01 +00:00
if ( SEqualNoCase ( sName . getData ( ) , pCheck - > szName ) ) break ; else + + pCheck ;
2009-05-08 13:28:41 +00:00
return pCheck - > eShift ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4KeyCodeEx : : KeyShift2String ( C4KeyShiftState eShift )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// query map
const C4KeyShiftMapEntry * pCheck = KeyShiftMap ;
while ( pCheck - > szName )
2010-03-28 18:58:01 +00:00
if ( eShift = = pCheck - > eShift ) break ; else + + pCheck ;
2009-05-08 13:28:41 +00:00
return StdStrBuf ( pCheck - > szName ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
struct C4KeyCodeMapEntry
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4KeyCode wCode ;
const char * szName ;
const char * szShortName ;
2010-03-28 18:58:01 +00:00
} ;
2009-05-08 13:28:41 +00:00
2016-02-06 14:44:19 +00:00
# if defined(USE_COCOA)
2016-04-03 18:07:56 +00:00
# include "platform/CocoaKeycodeMap.h"
2016-02-06 14:44:19 +00:00
# else
2013-02-09 00:03:06 +00:00
const C4KeyCodeMapEntry KeyCodeMap [ ] = {
2016-02-06 14:49:50 +00:00
{ K_ESCAPE , " Escape " , " Esc " } ,
2016-11-02 23:58:02 +00:00
{ K_1 , " 1 " , nullptr } ,
{ K_2 , " 2 " , nullptr } ,
{ K_3 , " 3 " , nullptr } ,
{ K_4 , " 4 " , nullptr } ,
{ K_5 , " 5 " , nullptr } ,
{ K_6 , " 6 " , nullptr } ,
{ K_7 , " 7 " , nullptr } ,
{ K_8 , " 8 " , nullptr } ,
{ K_9 , " 9 " , nullptr } ,
{ K_0 , " 0 " , nullptr } ,
2016-02-06 14:49:50 +00:00
{ K_MINUS , " Minus " , " - " } ,
{ K_EQUAL , " Equal " , " = " } ,
2016-11-02 23:58:02 +00:00
{ K_BACK , " BackSpace " , nullptr } ,
{ K_TAB , " Tab " , nullptr } ,
{ K_Q , " Q " , nullptr } ,
{ K_W , " W " , nullptr } ,
{ K_E , " E " , nullptr } ,
{ K_R , " R " , nullptr } ,
{ K_T , " T " , nullptr } ,
{ K_Y , " Y " , nullptr } ,
{ K_U , " U " , nullptr } ,
{ K_I , " I " , nullptr } ,
{ K_O , " O " , nullptr } ,
{ K_P , " P " , nullptr } ,
2016-02-06 14:49:50 +00:00
{ K_LEFT_BRACKET , " LeftBracket " , " [ " } ,
{ K_RIGHT_BRACKET , " RightBracket " , " ] " } ,
{ K_RETURN , " Return " , " Ret " } ,
{ K_CONTROL_L , " LeftControl " , " LCtrl " } ,
2016-11-02 23:58:02 +00:00
{ K_A , " A " , nullptr } ,
{ K_S , " S " , nullptr } ,
{ K_D , " D " , nullptr } ,
{ K_F , " F " , nullptr } ,
{ K_G , " G " , nullptr } ,
{ K_H , " H " , nullptr } ,
{ K_J , " J " , nullptr } ,
{ K_K , " K " , nullptr } ,
{ K_L , " L " , nullptr } ,
2016-02-06 14:49:50 +00:00
{ K_SEMICOLON , " Semicolon " , " ; " } ,
{ K_APOSTROPHE , " Apostrophe " , " ' " } ,
{ K_GRAVE_ACCENT , " GraveAccent " , " ` " } ,
{ K_SHIFT_L , " LeftShift " , " LShift " } ,
2017-05-03 18:28:00 +00:00
{ K_BACKSLASH , " Backslash " , R " ( \ ) " } ,
2016-11-02 23:58:02 +00:00
{ K_Z , " Z " , nullptr } ,
{ K_X , " X " , nullptr } ,
{ K_C , " C " , nullptr } ,
{ K_V , " V " , nullptr } ,
{ K_B , " B " , nullptr } ,
{ K_N , " N " , nullptr } ,
{ K_M , " M " , nullptr } ,
2016-02-06 14:49:50 +00:00
{ K_COMMA , " Comma " , " , " } ,
{ K_PERIOD , " Period " , " . " } ,
{ K_SLASH , " Slash " , " / " } ,
{ K_SHIFT_R , " RightShift " , " RShift " } ,
{ K_MULTIPLY , " Multiply " , " N* " } ,
{ K_ALT_L , " LeftAlt " , " LAlt " } ,
{ K_SPACE , " Space " , " Sp " } ,
2016-11-02 23:58:02 +00:00
{ K_CAPS , " Capslock " , nullptr } ,
{ K_F1 , " F1 " , nullptr } ,
{ K_F2 , " F2 " , nullptr } ,
{ K_F3 , " F3 " , nullptr } ,
{ K_F4 , " F4 " , nullptr } ,
{ K_F5 , " F5 " , nullptr } ,
{ K_F6 , " F6 " , nullptr } ,
{ K_F7 , " F7 " , nullptr } ,
{ K_F8 , " F8 " , nullptr } ,
{ K_F9 , " F9 " , nullptr } ,
{ K_F10 , " F10 " , nullptr } ,
2016-02-06 14:49:50 +00:00
{ K_NUM , " NumLock " , " NLock " } ,
{ K_SCROLL , " ScrollLock " , " SLock " } ,
{ K_NUM7 , " Num7 " , " N7 " } ,
{ K_NUM8 , " Num8 " , " N8 " } ,
{ K_NUM9 , " Num9 " , " N9 " } ,
{ K_SUBTRACT , " Subtract " , " N- " } ,
{ K_NUM4 , " Num4 " , " N4 " } ,
{ K_NUM5 , " Num5 " , " N5 " } ,
{ K_NUM6 , " Num6 " , " N6 " } ,
{ K_ADD , " Add " , " N+ " } ,
{ K_NUM1 , " Num1 " , " N1 " } ,
{ K_NUM2 , " Num2 " , " N2 " } ,
{ K_NUM3 , " Num3 " , " N3 " } ,
{ K_NUM0 , " Num0 " , " N0 " } ,
{ K_DECIMAL , " Decimal " , " N, " } ,
2016-11-02 23:58:02 +00:00
{ K_86 , " |<> " , nullptr } ,
{ K_F11 , " F11 " , nullptr } ,
{ K_F12 , " F12 " , nullptr } ,
2016-02-06 14:49:50 +00:00
{ K_NUM_RETURN , " NumReturn " , " NRet " } ,
{ K_CONTROL_R , " RightControl " , " RCtrl " } ,
{ K_DIVIDE , " Divide " , " N/ " } ,
{ K_ALT_R , " RightAlt " , " RAlt " } ,
2016-11-02 23:58:02 +00:00
{ K_HOME , " Home " , nullptr } ,
{ K_UP , " Up " , nullptr } ,
{ K_PAGEUP , " PageUp " , nullptr } ,
{ K_LEFT , " Left " , nullptr } ,
{ K_RIGHT , " Right " , nullptr } ,
{ K_END , " End " , nullptr } ,
{ K_DOWN , " Down " , nullptr } ,
{ K_PAGEDOWN , " PageDown " , nullptr } ,
2016-02-06 14:49:50 +00:00
{ K_INSERT , " Insert " , " Ins " } ,
{ K_DELETE , " Delete " , " Del " } ,
2016-11-02 23:58:02 +00:00
{ K_PAUSE , " Pause " , nullptr } ,
2016-02-06 14:49:50 +00:00
{ K_WIN_L , " LeftWin " , " LWin " } ,
{ K_WIN_R , " RightWin " , " RWin " } ,
2016-11-02 23:58:02 +00:00
{ K_MENU , " Menu " , nullptr } ,
{ K_PRINT , " Print " , nullptr } ,
{ 0x00 , nullptr , nullptr }
2010-03-28 18:58:01 +00:00
} ;
2009-05-08 13:28:41 +00:00
# endif
2018-01-17 23:40:39 +00:00
C4KeyCodeEx : : C4KeyCodeEx ( C4KeyCode key , DWORD Shift , bool fIsRepeated , int32_t deviceId )
2016-02-20 21:25:07 +00:00
: Key ( key ) , dwShift ( Shift ) , fRepeated ( fIsRepeated ) , deviceId ( deviceId )
{
}
2018-01-17 23:40:39 +00:00
C4KeyCodeEx C4KeyCodeEx : : FromC4MC ( int8_t mouse_id , int32_t iButton , DWORD dwKeyParam , bool * is_down )
{
bool dummy ;
if ( ! is_down )
is_down = & dummy ;
* is_down = true ;
C4KeyCode mouseevent_code ;
int wheel_dir = 0 ;
if ( iButton = = C4MC_Button_Wheel ) wheel_dir = ( short ) ( dwKeyParam > > 16 ) ;
switch ( iButton )
{
case C4MC_Button_None : mouseevent_code = KEY_MOUSE_Move ; break ;
case C4MC_Button_LeftDown : mouseevent_code = KEY_MOUSE_ButtonLeft ; break ;
case C4MC_Button_LeftUp : mouseevent_code = KEY_MOUSE_ButtonLeft ; * is_down = false ; break ;
case C4MC_Button_LeftDouble : mouseevent_code = KEY_MOUSE_ButtonLeftDouble ; break ;
case C4MC_Button_RightDown : mouseevent_code = KEY_MOUSE_ButtonRight ; break ;
case C4MC_Button_RightDouble : mouseevent_code = KEY_MOUSE_ButtonRightDouble ; break ;
case C4MC_Button_RightUp : mouseevent_code = KEY_MOUSE_ButtonRight ; * is_down = false ; break ;
case C4MC_Button_MiddleDown : mouseevent_code = KEY_MOUSE_ButtonMiddle ; break ;
case C4MC_Button_MiddleUp : mouseevent_code = KEY_MOUSE_ButtonMiddle ; * is_down = false ; break ;
case C4MC_Button_MiddleDouble : mouseevent_code = KEY_MOUSE_ButtonMiddleDouble ; break ;
case C4MC_Button_X1Down : mouseevent_code = KEY_MOUSE_ButtonX1 ; break ;
case C4MC_Button_X1Up : mouseevent_code = KEY_MOUSE_ButtonX1 ; * is_down = false ; break ;
case C4MC_Button_X1Double : mouseevent_code = KEY_MOUSE_ButtonX1Double ; break ;
case C4MC_Button_X2Down : mouseevent_code = KEY_MOUSE_ButtonX2 ; break ;
case C4MC_Button_X2Up : mouseevent_code = KEY_MOUSE_ButtonX2 ; * is_down = false ; break ;
case C4MC_Button_X2Double : mouseevent_code = KEY_MOUSE_ButtonX2Double ; break ;
case C4MC_Button_Wheel :
if ( ! wheel_dir ) assert ( " Attempted to record mouse wheel movement without a direction " ) ;
mouseevent_code = ( wheel_dir > 0 ) ? KEY_MOUSE_Wheel1Up : KEY_MOUSE_Wheel1Down ; break ;
}
C4KeyCodeEx key { KEY_Mouse ( mouse_id , mouseevent_code ) , KEYS_None } ;
if ( dwKeyParam & MK_CONTROL ) key . dwShift | = KEYS_Control ;
if ( dwKeyParam & MK_SHIFT ) key . dwShift | = KEYS_Shift ;
if ( dwKeyParam & MK_ALT ) key . dwShift | = KEYS_Alt ;
return key ;
}
2015-09-01 23:10:34 +00:00
void C4KeyCodeEx : : FixShiftKeys ( )
{
// reduce stuff like Ctrl+RightCtrl to simply RightCtrl
2018-01-17 23:40:39 +00:00
if ( ( dwShift & KEYS_Alt ) & & ( Key = = K_ALT_L | | Key = = K_ALT_R ) ) dwShift & = ~ KEYS_Alt ;
2015-09-01 23:10:34 +00:00
if ( ( dwShift & KEYS_Control ) & & ( Key = = K_CONTROL_L | | Key = = K_CONTROL_R ) ) dwShift & = ~ KEYS_Control ;
if ( ( dwShift & KEYS_Shift ) & & ( Key = = K_SHIFT_L | | Key = = K_SHIFT_R ) ) dwShift & = ~ KEYS_Shift ;
}
2012-10-08 22:54:34 +00:00
C4KeyCode C4KeyCodeEx : : GetKeyByScanCode ( const char * scan_code )
{
// scan code is in hex format
unsigned int scan_code_int ;
if ( sscanf ( scan_code , " $%x " , & scan_code_int ) ! = 1 ) return KEY_Undefined ;
2013-02-09 00:03:06 +00:00
return scan_code_int ;
2012-10-08 22:54:34 +00:00
}
2016-02-19 15:16:33 +00:00
static const std : : unordered_map < std : : string , C4KeyCode > controllercodes =
{
{ " ButtonA " , KEY_CONTROLLER_ButtonA } ,
{ " ButtonB " , KEY_CONTROLLER_ButtonB } ,
{ " ButtonX " , KEY_CONTROLLER_ButtonX } ,
{ " ButtonY " , KEY_CONTROLLER_ButtonY } ,
{ " ButtonBack " , KEY_CONTROLLER_ButtonBack } ,
{ " ButtonGuide " , KEY_CONTROLLER_ButtonGuide } ,
{ " ButtonStart " , KEY_CONTROLLER_ButtonStart } ,
{ " ButtonLeftStick " , KEY_CONTROLLER_ButtonLeftStick } ,
{ " ButtonRightStick " , KEY_CONTROLLER_ButtonRightStick } ,
{ " ButtonLeftShoulder " , KEY_CONTROLLER_ButtonLeftShoulder } ,
{ " ButtonRightShoulder " , KEY_CONTROLLER_ButtonRightShoulder } ,
{ " ButtonDpadUp " , KEY_CONTROLLER_ButtonDpadUp } ,
{ " ButtonDpadDown " , KEY_CONTROLLER_ButtonDpadDown } ,
{ " ButtonDpadLeft " , KEY_CONTROLLER_ButtonDpadLeft } ,
{ " ButtonDpadRight " , KEY_CONTROLLER_ButtonDpadRight } ,
{ " AnyButton " , KEY_CONTROLLER_AnyButton } ,
{ " LeftStickLeft " , KEY_CONTROLLER_AxisLeftXLeft } ,
{ " LeftStickRight " , KEY_CONTROLLER_AxisLeftXRight } ,
{ " LeftStickUp " , KEY_CONTROLLER_AxisLeftYUp } ,
{ " LeftStickDown " , KEY_CONTROLLER_AxisLeftYDown } ,
{ " RightStickLeft " , KEY_CONTROLLER_AxisRightXLeft } ,
{ " RightStickRight " , KEY_CONTROLLER_AxisRightXRight } ,
{ " RightStickUp " , KEY_CONTROLLER_AxisRightYUp } ,
{ " RightStickDown " , KEY_CONTROLLER_AxisRightYDown } ,
{ " LeftTrigger " , KEY_CONTROLLER_AxisTriggerLeft } ,
{ " RightTrigger " , KEY_CONTROLLER_AxisTriggerRight } ,
} ;
2009-05-08 13:28:41 +00:00
C4KeyCode C4KeyCodeEx : : String2KeyCode ( const StdStrBuf & sName )
2009-10-16 14:23:17 +00:00
{
2017-12-28 19:48:52 +00:00
// direct key code, e.g. "$e" (Backspace)?
if ( sName . getLength ( ) > 1 )
2009-10-16 14:23:17 +00:00
{
2010-04-28 21:43:25 +00:00
unsigned int dwRVal ;
2017-05-03 18:28:00 +00:00
if ( sscanf ( sName . getData ( ) , R " ( \ x%x) " , & dwRVal ) = = 1 ) return dwRVal ;
2012-10-08 22:54:34 +00:00
// scan code
if ( * sName . getData ( ) = = ' $ ' ) return GetKeyByScanCode ( sName . getData ( ) ) ;
2009-05-08 13:28:41 +00:00
// direct gamepad code
2016-02-19 15:16:33 +00:00
std : : regex controller_re ( R " /(^Controller( \ w+)$)/ " ) ;
2016-02-13 22:28:00 +00:00
std : : cmatch matches ;
if ( std : : regex_match ( sName . getData ( ) , matches , controller_re ) )
2009-10-16 14:23:17 +00:00
{
2016-02-19 15:16:33 +00:00
auto keycode_it = controllercodes . find ( matches [ 1 ] . str ( ) ) ;
if ( keycode_it ! = controllercodes . end ( ) )
2016-02-20 21:25:07 +00:00
return KEY_Gamepad ( keycode_it - > second ) ;
2016-02-13 22:28:00 +00:00
else
2016-02-19 15:16:33 +00:00
return KEY_Undefined ;
2009-05-08 13:28:41 +00:00
}
2011-11-20 20:49:38 +00:00
bool is_mouse_key ;
2009-10-17 15:53:26 +00:00
# ifdef _WIN32
is_mouse_key = ! strnicmp ( sName . getData ( ) , " Mouse " , 5 ) ;
# else
is_mouse_key = ! strncasecmp ( sName . getData ( ) , " Mouse " , 5 ) ;
# endif
2011-11-20 20:49:38 +00:00
if ( is_mouse_key )
2009-10-17 15:53:26 +00:00
{
// skip Mouse/GameMouse
const char * key_str = sName . getData ( ) + 5 ;
int mouse_id ;
if ( sscanf ( key_str , " %d " , & mouse_id ) = = 1 )
{
// skip number
while ( isdigit ( * key_str ) ) + + key_str ;
2018-01-17 23:40:39 +00:00
// check for known mouse events (e.g. Mouse0Move or GameMouse0Wheel)
if ( ! stricmp ( key_str , " Move " ) ) return KEY_Mouse ( mouse_id , KEY_MOUSE_Move ) ;
if ( ! stricmp ( key_str , " Wheel1Up " ) ) return KEY_Mouse ( mouse_id , KEY_MOUSE_Wheel1Up ) ;
if ( ! stricmp ( key_str , " Wheel1Down " ) ) return KEY_Mouse ( mouse_id , KEY_MOUSE_Wheel1Down ) ;
// check for known mouse button events
if ( SEqualNoCase ( key_str , " Button " , 6 ) ) // e.g. Mouse0ButtonLeft or GameMouse0ButtonRightDouble (This line is left here to not break anything, the buttons are now named Mouse0Left)
2009-10-17 15:53:26 +00:00
key_str + = 6 ;
2018-01-17 23:40:39 +00:00
uint8_t mouseevent_id = 0 ;
if ( SEqualNoCase ( key_str , " Left " , 4 ) ) { mouseevent_id = KEY_MOUSE_ButtonLeft ; key_str + = 4 ; }
else if ( SEqualNoCase ( key_str , " Right " , 5 ) ) { mouseevent_id = KEY_MOUSE_ButtonRight ; key_str + = 5 ; }
else if ( SEqualNoCase ( key_str , " Middle " , 6 ) ) { mouseevent_id = KEY_MOUSE_ButtonMiddle ; key_str + = 6 ; }
else if ( SEqualNoCase ( key_str , " X1 " , 2 ) ) { mouseevent_id = KEY_MOUSE_ButtonX1 ; key_str + = 2 ; }
else if ( SEqualNoCase ( key_str , " X2 " , 2 ) ) { mouseevent_id = KEY_MOUSE_ButtonX2 ; key_str + = 2 ; }
else if ( isdigit ( * key_str ) )
{
// indexed mouse button (e.g. Mouse0Button4 or Mouse0Button4Double)
int button_index ;
if ( sscanf ( key_str , " %d " , & button_index ) = = 1 )
2009-10-17 15:53:26 +00:00
{
2018-01-17 23:40:39 +00:00
mouseevent_id = static_cast < uint8_t > ( KEY_MOUSE_Button1 + button_index ) ;
while ( isdigit ( * key_str ) ) + + key_str ;
2009-10-17 15:53:26 +00:00
}
}
2018-01-17 23:40:39 +00:00
if ( mouseevent_id )
{
// valid event if finished or followed by "Double"
if ( ! * key_str ) return KEY_Mouse ( mouse_id , mouseevent_id ) ;
if ( ! stricmp ( key_str , " Double " ) ) return KEY_Mouse ( mouse_id , mouseevent_id + ( KEY_MOUSE_Button1Double - KEY_MOUSE_Button1 ) ) ;
// invalid mouse key...
}
2009-10-17 15:53:26 +00:00
}
}
2009-10-16 14:23:17 +00:00
}
2009-05-08 13:28:41 +00:00
// query map
const C4KeyCodeMapEntry * pCheck = KeyCodeMap ;
2013-02-09 00:03:06 +00:00
while ( pCheck - > szName ) {
if ( SEqualNoCase ( sName . getData ( ) , pCheck - > szName ) ) {
return ( pCheck - > wCode ) ;
}
+ + pCheck ;
2010-01-27 21:36:27 +00:00
}
2016-02-06 14:44:19 +00:00
# if defined(USE_SDL_MAINLOOP)
SDL_Scancode s = SDL_GetScancodeFromName ( sName . getData ( ) ) ;
if ( s ! = SDL_SCANCODE_UNKNOWN ) return s ;
2009-05-08 13:28:41 +00:00
# endif
2016-02-06 14:44:19 +00:00
return KEY_Undefined ;
2009-10-16 14:23:17 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4KeyCodeEx : : KeyCode2String ( C4KeyCode wCode , bool fHumanReadable , bool fShort )
2009-10-17 15:53:26 +00:00
{
2009-05-08 13:28:41 +00:00
// Gamepad keys
if ( Key_IsGamepad ( wCode ) )
2009-10-17 15:53:26 +00:00
{
2016-02-19 15:16:33 +00:00
if ( fHumanReadable )
2016-02-13 22:28:00 +00:00
{
2016-02-19 15:16:33 +00:00
switch ( Key_GetGamepadEvent ( wCode ) )
2016-02-13 22:28:00 +00:00
{
2016-02-19 19:17:05 +00:00
case KEY_CONTROLLER_ButtonA : return StdStrBuf ( " {{@Ico:A}} " ) ;
case KEY_CONTROLLER_ButtonB : return StdStrBuf ( " {{@Ico:B}} " ) ;
case KEY_CONTROLLER_ButtonX : return StdStrBuf ( " {{@Ico:X}} " ) ;
case KEY_CONTROLLER_ButtonY : return StdStrBuf ( " {{@Ico:Y}} " ) ;
case KEY_CONTROLLER_ButtonBack : return StdStrBuf ( " {{@Ico:Back}} " ) ;
2016-02-19 15:16:33 +00:00
case KEY_CONTROLLER_ButtonGuide : return StdStrBuf ( " Guide " ) ;
2016-02-19 19:17:05 +00:00
case KEY_CONTROLLER_ButtonStart : return StdStrBuf ( " {{@Ico:Start}} " ) ;
case KEY_CONTROLLER_ButtonLeftStick : return StdStrBuf ( " {{@Ico:LeftStick}} " ) ;
case KEY_CONTROLLER_ButtonRightStick : return StdStrBuf ( " {{@Ico:RightStick}} " ) ;
case KEY_CONTROLLER_ButtonLeftShoulder : return StdStrBuf ( " {{@Ico:LeftShoulder}} " ) ;
case KEY_CONTROLLER_ButtonRightShoulder : return StdStrBuf ( " {{@Ico:RightShoulder}} " ) ;
case KEY_CONTROLLER_ButtonDpadUp : return StdStrBuf ( " {{@Ico:DpadUp}} " ) ;
case KEY_CONTROLLER_ButtonDpadDown : return StdStrBuf ( " {{@Ico:DpadDown}} " ) ;
case KEY_CONTROLLER_ButtonDpadLeft : return StdStrBuf ( " {{@Ico:DpadLeft}} " ) ;
case KEY_CONTROLLER_ButtonDpadRight : return StdStrBuf ( " {{@Ico:DpadRight}} " ) ;
2016-02-19 15:16:33 +00:00
case KEY_CONTROLLER_AnyButton : return StdStrBuf ( " Any Button " ) ;
2016-02-19 19:17:05 +00:00
case KEY_CONTROLLER_AxisLeftXLeft : return StdStrBuf ( " {{@Ico:LeftStick}} Left " ) ;
case KEY_CONTROLLER_AxisLeftXRight : return StdStrBuf ( " {{@Ico:LeftStick}} Right " ) ;
case KEY_CONTROLLER_AxisLeftYUp : return StdStrBuf ( " {{@Ico:LeftStick}} Up " ) ;
case KEY_CONTROLLER_AxisLeftYDown : return StdStrBuf ( " {{@Ico:LeftStick}} Down " ) ;
case KEY_CONTROLLER_AxisRightXLeft : return StdStrBuf ( " {{@Ico:RightStick}} Left " ) ;
case KEY_CONTROLLER_AxisRightXRight : return StdStrBuf ( " {{@Ico:RightStick}} Right " ) ;
case KEY_CONTROLLER_AxisRightYUp : return StdStrBuf ( " {{@Ico:RightStick}} Up " ) ;
case KEY_CONTROLLER_AxisRightYDown : return StdStrBuf ( " {{@Ico:RightStick}} Down " ) ;
case KEY_CONTROLLER_AxisTriggerLeft : return StdStrBuf ( " {{@Ico:LeftTrigger}} " ) ;
case KEY_CONTROLLER_AxisTriggerRight : return StdStrBuf ( " {{@Ico:RightTrigger}} " ) ;
2016-02-13 22:28:00 +00:00
}
}
else
2009-10-17 15:53:26 +00:00
{
2016-02-19 15:16:33 +00:00
// A linear search in our small map is probably fast enough.
auto it = std : : find_if ( controllercodes . begin ( ) , controllercodes . end ( ) , [ wCode ] ( const auto & p )
2010-03-28 18:58:01 +00:00
{
2016-02-19 15:16:33 +00:00
return p . second = = Key_GetGamepadEvent ( wCode ) ;
} ) ;
if ( it ! = controllercodes . end ( ) )
return FormatString ( " Controller%s " , it - > first . c_str ( ) ) ;
2009-05-08 13:28:41 +00:00
}
2016-02-19 15:16:33 +00:00
return StdStrBuf ( " Unknown " ) ;
2009-10-17 15:53:26 +00:00
}
2016-02-19 15:16:33 +00:00
2009-10-17 15:53:26 +00:00
// Mouse keys
if ( Key_IsMouse ( wCode ) )
{
int mouse_id = Key_GetMouse ( wCode ) ;
int mouse_event = Key_GetMouseEvent ( wCode ) ;
2011-11-20 20:49:38 +00:00
const char * mouse_str = " Mouse " ;
2009-10-17 15:53:26 +00:00
switch ( mouse_event )
{
2011-11-20 20:49:38 +00:00
case KEY_MOUSE_Move : return FormatString ( " %s%dMove " , mouse_str , mouse_id ) ;
case KEY_MOUSE_Wheel1Up : return FormatString ( " %s%dWheel1Up " , mouse_str , mouse_id ) ;
case KEY_MOUSE_Wheel1Down : return FormatString ( " %s%dWheel1Down " , mouse_str , mouse_id ) ;
case KEY_MOUSE_ButtonLeft : return FormatString ( " %s%dLeft " , mouse_str , mouse_id ) ;
case KEY_MOUSE_ButtonRight : return FormatString ( " %s%dRight " , mouse_str , mouse_id ) ;
case KEY_MOUSE_ButtonMiddle : return FormatString ( " %s%dMiddle " , mouse_str , mouse_id ) ;
2016-08-18 20:43:42 +00:00
case KEY_MOUSE_ButtonX1 : return FormatString ( " %s%dX1 " , mouse_str , mouse_id ) ;
case KEY_MOUSE_ButtonX2 : return FormatString ( " %s%dX2 " , mouse_str , mouse_id ) ;
2011-11-20 20:49:38 +00:00
case KEY_MOUSE_ButtonLeftDouble : return FormatString ( " %s%dLeftDouble " , mouse_str , mouse_id ) ;
case KEY_MOUSE_ButtonRightDouble : return FormatString ( " %s%dRightDouble " , mouse_str , mouse_id ) ;
case KEY_MOUSE_ButtonMiddleDouble : return FormatString ( " %s%dMiddleDouble " , mouse_str , mouse_id ) ;
2016-08-18 20:43:42 +00:00
case KEY_MOUSE_ButtonX1Double : return FormatString ( " %s%dX1Double " , mouse_str , mouse_id ) ;
case KEY_MOUSE_ButtonX2Double : return FormatString ( " %s%dX2Double " , mouse_str , mouse_id ) ;
2010-03-28 18:58:01 +00:00
default :
// extended mouse button
{
uint8_t btn = Key_GetMouseEvent ( wCode ) ;
if ( btn > = KEY_MOUSE_Button1Double )
2011-11-20 20:49:38 +00:00
return FormatString ( " %s%dButton%dDouble " , mouse_str , mouse_id , int ( btn - KEY_MOUSE_Button1Double ) ) ;
2010-03-28 18:58:01 +00:00
else
2011-11-20 20:49:38 +00:00
return FormatString ( " %s%dButton%d " , mouse_str , mouse_id , int ( btn - KEY_MOUSE_Button1 ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-10-17 15:53:26 +00:00
}
}
2013-02-09 00:03:06 +00:00
// it's a keyboard key
if ( ! fHumanReadable ) {
// for config files and such: dump scancode
return FormatString ( " $%x " , static_cast < unsigned int > ( wCode ) ) ;
}
2016-08-03 14:10:36 +00:00
# if defined(USE_WIN32_WINDOWS)
2009-05-08 13:28:41 +00:00
2015-09-01 00:50:28 +00:00
// Query map
const C4KeyCodeMapEntry * pCheck = KeyCodeMap ;
while ( pCheck - > szName )
if ( wCode = = pCheck - > wCode ) return StdStrBuf ( ( pCheck - > szShortName & & fShort ) ? pCheck - > szShortName : pCheck - > szName ) ; else + + pCheck ;
2010-03-28 18:58:01 +00:00
// TODO: Works?
// StdStrBuf Name; Name.SetLength(1000);
// int res = GetKeyNameText(wCode, Name.getMData(), Name.getSize());
// if(!res)
// // not found: Compose as direct code
// return FormatString("\\x%x", (DWORD) wCode);
// // Set size
// Name.SetLength(res);
// return Name;
2009-05-08 13:28:41 +00:00
2013-02-09 00:03:06 +00:00
wchar_t buf [ 100 ] ;
int len = GetKeyNameText ( wCode < < 16 , buf , 100 ) ;
if ( len > 0 ) {
// buf is nullterminated name
return StdStrBuf ( buf ) ;
}
2013-05-24 17:24:31 +00:00
# elif defined (USE_COCOA)
// query map
const C4KeyCodeMapEntry * pCheck = KeyCodeMap ;
while ( pCheck - > szName )
if ( wCode = = pCheck - > wCode ) return StdStrBuf ( ( pCheck - > szShortName & & fShort ) ? pCheck - > szShortName : pCheck - > szName ) ; else + + pCheck ;
// not found: Compose as direct code
return FormatString ( " \\ x%x " , static_cast < unsigned int > ( wCode ) ) ;
2009-05-08 13:28:41 +00:00
# elif defined(USE_SDL_MAINLOOP)
2016-02-06 14:44:19 +00:00
StdStrBuf buf ;
2016-08-20 21:15:53 +00:00
auto name = KeycodeToString ( wCode ) ;
if ( name ) buf . Copy ( name ) ;
2016-10-31 22:39:27 +00:00
if ( ! buf . getLength ( ) ) buf . Format ( " \\ x%lx " , wCode ) ;
2016-02-06 14:44:19 +00:00
return buf ;
2009-05-08 13:28:41 +00:00
# endif
2013-02-09 00:03:06 +00:00
return FormatString ( " $%x " , static_cast < unsigned int > ( wCode ) ) ;
2009-10-17 15:53:26 +00:00
}
2009-05-08 13:28:41 +00:00
2012-04-17 15:06:16 +00:00
StdStrBuf C4KeyCodeEx : : ToString ( bool fHumanReadable , bool fShort ) const
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
static StdStrBuf sResult ;
sResult . Clear ( ) ;
// Add shift
for ( DWORD dwShiftCheck = KEYS_First ; dwShiftCheck < = KEYS_Max ; dwShiftCheck < < = 1 )
if ( dwShiftCheck & dwShift )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sResult . Append ( KeyShift2String ( ( C4KeyShiftState ) dwShiftCheck ) ) ;
sResult . AppendChar ( ' + ' ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Add key
if ( sResult . getLength ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
sResult . Append ( KeyCode2String ( Key , fHumanReadable , fShort ) ) ;
return sResult ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
return KeyCode2String ( Key , fHumanReadable , fShort ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
/* ----------------- C4KeyCodeEx ------------------ */
2012-10-08 22:54:34 +00:00
void C4KeyCodeEx : : CompileFunc ( StdCompiler * pComp , StdStrBuf * pOutBuf )
2010-03-28 18:58:01 +00:00
{
2017-03-11 14:05:41 +00:00
if ( pComp - > isDeserializer ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// reading from file
StdStrBuf sCode ;
2012-10-08 22:54:34 +00:00
bool is_scan_code ;
// read shifts
2009-05-08 13:28:41 +00:00
DWORD dwSetShift = 0 ;
2010-03-28 18:58:01 +00:00
for ( ; ; )
{
2012-10-08 22:54:34 +00:00
is_scan_code = pComp - > Separator ( StdCompiler : : SEP_DOLLAR ) ;
if ( ! is_scan_code ) pComp - > NoSeparator ( ) ;
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkParAdapt ( sCode , StdCompiler : : RCT_Idtf ) ) ;
2012-10-08 22:54:34 +00:00
if ( is_scan_code ) // scan codes start with $. Reassamble the two tokens that were split by StdCompiler
{
sCode . Take ( FormatString ( " $%s " , sCode . getData ( ) ) ) ;
break ;
}
2010-04-01 21:08:06 +00:00
if ( ! pComp - > Separator ( StdCompiler : : SEP_PLUS ) ) break ; // no more separator: Parse this as keyboard code
2009-05-08 13:28:41 +00:00
// try to convert to shift state
C4KeyShiftState eAddState = String2KeyShift ( sCode ) ;
if ( eAddState = = KEYS_Undefined )
pComp - > excCorrupt ( " undefined key shift state: %s " , sCode . getData ( ) ) ;
dwSetShift | = eAddState ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// any code given? Otherwise, keep default
if ( sCode . getLength ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// last section: convert to key code
C4KeyCode eCode = String2KeyCode ( sCode ) ;
if ( eCode = = KEY_Undefined )
2010-03-28 18:58:01 +00:00
{
2012-10-08 22:54:34 +00:00
if ( pOutBuf )
2010-03-28 18:58:01 +00:00
{
2012-10-08 22:54:34 +00:00
// unknown key, but an output buffer for unknown keys was provided. No failure; caller might resolve key.
2009-05-25 09:01:26 +00:00
eCode = KEY_Default ;
2010-03-28 18:58:01 +00:00
}
2009-05-25 09:01:26 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-25 09:01:26 +00:00
pComp - > excCorrupt ( " undefined key code: %s " , sCode . getData ( ) ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
dwShift = dwSetShift ;
Key = eCode ;
2018-01-17 23:40:39 +00:00
if ( pOutBuf ) {
// FIXME: This function is used both, to deserialize things like CON_Right and Shift+$12
// For CON_…, eCode and dwShift will be zero, and sCode will contain the key name.
// For Shift+… sCode will only contain the last token. What is correct here?
// Reading C4PlayerControlAssignment::KeyComboItem::CompileFunc suggests that setting not value for parsed combinations may be correct.
if ( eCode = = 0 )
pOutBuf - > Take ( std : : move ( sCode ) ) ;
else
pOutBuf - > Copy ( ToString ( false , false ) ) ;
}
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// write shift states
for ( DWORD dwShiftCheck = KEYS_First ; dwShiftCheck < = KEYS_Max ; dwShiftCheck < < = 1 )
if ( dwShiftCheck & dwShift )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkDecompileAdapt ( KeyShift2String ( ( C4KeyShiftState ) dwShiftCheck ) ) ) ;
2010-04-01 21:08:06 +00:00
pComp - > Separator ( StdCompiler : : SEP_PLUS ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// write key
pComp - > Value ( mkDecompileAdapt ( KeyCode2String ( Key , false , false ) ) ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2009-05-26 06:10:38 +00:00
void C4KeyEventData : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
pComp - > Value ( iStrength ) ;
2010-04-01 21:08:06 +00:00
pComp - > Separator ( ) ;
2011-11-20 20:49:38 +00:00
pComp - > Value ( game_x ) ;
2010-04-01 21:08:06 +00:00
pComp - > Separator ( ) ;
2011-11-20 20:49:38 +00:00
pComp - > Value ( game_y ) ;
pComp - > Separator ( ) ;
pComp - > Value ( vp_x ) ;
pComp - > Separator ( ) ;
pComp - > Value ( vp_y ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
bool C4KeyEventData : : operator = = ( const struct C4KeyEventData & cmp ) const
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
return iStrength = = cmp . iStrength
2011-11-20 20:49:38 +00:00
& & game_x = = cmp . game_x & & game_y = = cmp . game_y
& & vp_x = = cmp . vp_x & & vp_y = = cmp . vp_y ;
2010-03-28 18:58:01 +00:00
}
2009-05-26 06:10:38 +00:00
2018-01-19 12:01:26 +00:00
bool KEY_IsModifier ( C4KeyCode k ) {
return k = = K_CONTROL_L | | k = = K_SHIFT_L | | k = = K_ALT_L | |
k = = K_CONTROL_R | | k = = K_SHIFT_R | | k = = K_ALT_R ;
}
2009-05-08 13:28:41 +00:00
/* ----------------- C4CustomKey------------------ */
2009-05-28 00:14:54 +00:00
C4CustomKey : : C4CustomKey ( const C4KeyCodeEx & DefCode , const char * szName , C4KeyScope Scope , C4KeyboardCallbackInterface * pCallback , unsigned int uiPriority )
2016-01-09 04:17:11 +00:00
: Scope ( Scope ) , Name ( ) , uiPriority ( uiPriority ) , iRef ( 0 ) , is_down ( false )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// generate code
if ( DefCode . Key ! = KEY_Default ) DefaultCodes . push_back ( DefCode ) ;
// ctor for default key
Name . Copy ( szName ) ;
if ( pCallback )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pCallback - > Ref ( ) ;
vecCallbacks . push_back ( pCallback ) ;
pCallback - > pOriginalKey = this ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2017-05-03 18:28:00 +00:00
C4CustomKey : : C4CustomKey ( CodeList rDefCodes , const char * szName , C4KeyScope Scope , C4KeyboardCallbackInterface * pCallback , unsigned int uiPriority )
: DefaultCodes ( std : : move ( rDefCodes ) ) , Scope ( Scope ) , Name ( ) , uiPriority ( uiPriority ) , iRef ( 0 ) , is_down ( false )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// ctor for default key
Name . Copy ( szName ) ;
if ( pCallback )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pCallback - > Ref ( ) ;
vecCallbacks . push_back ( pCallback ) ;
pCallback - > pOriginalKey = this ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4CustomKey : : C4CustomKey ( const C4CustomKey & rCpy , bool fCopyCallbacks )
2016-04-25 20:17:10 +00:00
: Codes ( rCpy . Codes ) , DefaultCodes ( rCpy . DefaultCodes ) , Scope ( rCpy . Scope ) , Name ( ) , uiPriority ( rCpy . uiPriority ) , iRef ( 0 ) , is_down ( false )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
Name . Copy ( rCpy . GetName ( ) ) ;
if ( fCopyCallbacks )
2010-03-28 18:58:01 +00:00
{
2017-05-03 18:28:00 +00:00
for ( auto callback : rCpy . vecCallbacks )
2009-05-08 13:28:41 +00:00
{
2017-05-03 18:28:00 +00:00
callback - > Ref ( ) ;
vecCallbacks . push_back ( callback ) ;
2009-05-08 13:28:41 +00:00
}
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4CustomKey : : ~ C4CustomKey ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// free callback handles
2010-03-28 18:58:01 +00:00
for ( CBVec : : const_iterator i = vecCallbacks . begin ( ) ; i ! = vecCallbacks . end ( ) ; + + i )
2009-05-08 13:28:41 +00:00
( * i ) - > Deref ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2016-02-20 21:25:07 +00:00
bool C4CustomKey : : IsCodeMatched ( const C4KeyCodeEx & key ) const
{
const CodeList & codes = GetCodes ( ) ;
for ( const auto & code : codes )
if ( code = = key )
return true ;
return false ;
}
2009-05-08 13:28:41 +00:00
void C4CustomKey : : Update ( const C4CustomKey * pByKey )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( pByKey ) ;
assert ( Name = = pByKey - > Name ) ;
// transfer any assigned data, except name which should be equal anyway
if ( pByKey - > DefaultCodes . size ( ) ) DefaultCodes = pByKey - > DefaultCodes ;
if ( pByKey - > Codes . size ( ) ) Codes = pByKey - > Codes ;
if ( pByKey - > Scope ! = KEYSCOPE_None ) Scope = pByKey - > Scope ;
if ( pByKey - > uiPriority ! = PRIO_None ) uiPriority = pByKey - > uiPriority ;
2017-05-03 18:28:00 +00:00
for ( auto callback : pByKey - > vecCallbacks )
2010-03-28 18:58:01 +00:00
{
2017-05-03 18:28:00 +00:00
callback - > Ref ( ) ;
vecCallbacks . push_back ( callback ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4CustomKey : : KillCallbacks ( const C4CustomKey * pOfKey )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// remove all instances from list
CBVec : : iterator i ;
2018-07-24 12:21:42 +00:00
while ( ( i = std : : find_if ( vecCallbacks . begin ( ) , vecCallbacks . end ( ) , [ pOfKey ] ( CBVec : : value_type pIntfc ) { return pIntfc - > IsOriginalKey ( pOfKey ) ; } ) ) ! = vecCallbacks . end ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4KeyboardCallbackInterface * pItfc = * i ;
vecCallbacks . erase ( i ) ;
pItfc - > Deref ( ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4CustomKey : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
pComp - > Value ( mkNamingAdapt ( mkSTLContainerAdapt ( Codes ) , Name . getData ( ) , DefaultCodes ) ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
bool C4CustomKey : : Execute ( C4KeyEventType eEv , C4KeyCodeEx key )
2010-03-28 18:58:01 +00:00
{
2016-01-09 04:17:11 +00:00
// remember down-state
is_down = ( eEv = = KEYEV_Down ) ;
2009-05-08 13:28:41 +00:00
// execute all callbacks
2017-05-03 18:28:00 +00:00
for ( auto & callback : vecCallbacks )
if ( callback - > OnKeyEvent ( key , eEv ) )
2009-05-08 13:28:41 +00:00
return true ;
// no event processed it
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
/* ----------------- C4KeyBinding ------------------ */
2009-05-28 00:14:54 +00:00
C4KeyBinding : : C4KeyBinding ( const C4KeyCodeEx & DefCode , const char * szName , C4KeyScope Scope , C4KeyboardCallbackInterface * pCallback , unsigned int uiPriority )
2010-03-28 18:58:01 +00:00
: C4CustomKey ( DefCode , szName , Scope , pCallback , uiPriority )
{
2009-05-08 13:28:41 +00:00
// self holds a ref
Ref ( ) ;
// register into keyboard input class
C4KeyboardInput_Init ( ) . RegisterKey ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4KeyBinding : : C4KeyBinding ( const CodeList & rDefCodes , const char * szName , C4KeyScope Scope , C4KeyboardCallbackInterface * pCallback , unsigned int uiPriority )
2010-03-28 18:58:01 +00:00
: C4CustomKey ( rDefCodes , szName , Scope , pCallback , uiPriority )
{
2009-05-08 13:28:41 +00:00
// self holds a ref
Ref ( ) ;
// register into keyboard input class
C4KeyboardInput_Init ( ) . RegisterKey ( this ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4KeyBinding : : ~ C4KeyBinding ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// deregister from keyboard input class, if that class still exists
if ( C4KeyboardInput : : IsValid )
Game . KeyboardInput . UnregisterKeyBinding ( this ) ;
// shouldn't be refed now
assert ( iRef = = 1 ) ;
iRef = 0 ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
/* ----------------- C4KeyboardInput ------------------ */
bool C4KeyboardInput : : IsValid = false ;
void C4KeyboardInput : : Clear ( )
2010-03-28 18:58:01 +00:00
{
2009-05-26 06:10:38 +00:00
LastKeyExtraData = C4KeyEventData ( ) ;
2009-05-08 13:28:41 +00:00
// release all keys - name map is guarantueed to contain them all
for ( KeyNameMap : : const_iterator i = KeysByName . begin ( ) ; i ! = KeysByName . end ( ) ; + + i )
i - > second - > Deref ( ) ;
// clear maps
KeysByCode . clear ( ) ;
KeysByName . clear ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4KeyboardInput : : UpdateKeyCodes ( C4CustomKey * pKey , const C4CustomKey : : CodeList & rOldCodes , const C4CustomKey : : CodeList & rNewCodes )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// new key codes must be the new current key codes
assert ( pKey - > GetCodes ( ) = = rNewCodes ) ;
// kill from old list
C4CustomKey : : CodeList : : const_iterator iCode ;
for ( iCode = rOldCodes . begin ( ) ; iCode ! = rOldCodes . end ( ) ; + + iCode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no need to kill if code stayed
if ( std : : find ( rNewCodes . begin ( ) , rNewCodes . end ( ) , * iCode ) ! = rNewCodes . end ( ) ) continue ;
2010-02-18 17:43:38 +00:00
std : : pair < KeyCodeMap : : iterator , KeyCodeMap : : iterator > KeyRange = KeysByCode . equal_range ( ( * iCode ) . Key ) ;
2009-05-08 13:28:41 +00:00
for ( KeyCodeMap : : iterator i = KeyRange . first ; i ! = KeyRange . second ; + + i )
if ( i - > second = = pKey )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
KeysByCode . erase ( i ) ;
break ;
2010-03-28 18:58:01 +00:00
}
}
2009-05-08 13:28:41 +00:00
// readd new codes
for ( iCode = rNewCodes . begin ( ) ; iCode ! = rNewCodes . end ( ) ; + + iCode )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// no double-add if it was in old list already
if ( std : : find ( rOldCodes . begin ( ) , rOldCodes . end ( ) , * iCode ) ! = rOldCodes . end ( ) ) continue ;
2010-02-18 17:43:38 +00:00
KeysByCode . insert ( std : : make_pair ( ( * iCode ) . Key , pKey ) ) ;
2009-05-08 13:28:41 +00:00
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4KeyboardInput : : RegisterKey ( C4CustomKey * pRegKey )
2010-02-18 17:43:38 +00:00
{
2009-05-08 13:28:41 +00:00
assert ( pRegKey ) ; if ( ! pRegKey ) return ;
// key will be added: ref it
pRegKey - > Ref ( ) ;
// search key of same name first
C4CustomKey * pDupKey = KeysByName [ pRegKey - > GetName ( ) . getData ( ) ] ;
if ( pDupKey )
2010-02-18 17:43:38 +00:00
{
2009-05-08 13:28:41 +00:00
// key of this name exists: Merge them (old codes copied cuz they'll be overwritten)
C4CustomKey : : CodeList OldCodes = pDupKey - > GetCodes ( ) ;
const C4CustomKey : : CodeList & rNewCodes = pRegKey - > GetCodes ( ) ;
pDupKey - > Update ( pRegKey ) ;
// update access map if key changed
if ( ! ( OldCodes = = rNewCodes ) ) UpdateKeyCodes ( pDupKey , OldCodes , rNewCodes ) ;
// key to be registered no longer used
pRegKey - > Deref ( ) ;
2010-02-18 17:43:38 +00:00
}
2009-05-08 13:28:41 +00:00
else
2010-02-18 17:43:38 +00:00
{
// new unique key: Insert into map
2009-05-08 13:28:41 +00:00
KeysByName [ pRegKey - > GetName ( ) . getData ( ) ] = pRegKey ;
for ( C4CustomKey : : CodeList : : const_iterator i = pRegKey - > GetCodes ( ) . begin ( ) ; i ! = pRegKey - > GetCodes ( ) . end ( ) ; + + i )
2010-02-18 17:43:38 +00:00
{
KeysByCode . insert ( std : : make_pair ( ( * i ) . Key , pRegKey ) ) ;
2009-05-08 13:28:41 +00:00
}
}
2010-02-18 17:43:38 +00:00
}
2009-05-08 13:28:41 +00:00
void C4KeyboardInput : : UnregisterKey ( const StdStrBuf & rsName )
2010-02-18 17:43:38 +00:00
{
2009-05-08 13:28:41 +00:00
// kill from name map
KeyNameMap : : iterator in = KeysByName . find ( rsName . getData ( ) ) ;
if ( in = = KeysByName . end ( ) ) return ;
C4CustomKey * pKey = in - > second ;
KeysByName . erase ( in ) ;
// kill all key bindings from key map
for ( C4CustomKey : : CodeList : : const_iterator iCode = pKey - > GetCodes ( ) . begin ( ) ; iCode ! = pKey - > GetCodes ( ) . end ( ) ; + + iCode )
2010-02-18 17:43:38 +00:00
{
std : : pair < KeyCodeMap : : iterator , KeyCodeMap : : iterator > KeyRange = KeysByCode . equal_range ( ( * iCode ) . Key ) ;
2009-05-08 13:28:41 +00:00
for ( KeyCodeMap : : iterator i = KeyRange . first ; i ! = KeyRange . second ; + + i )
if ( i - > second = = pKey )
2010-02-18 17:43:38 +00:00
{
2009-05-08 13:28:41 +00:00
KeysByCode . erase ( i ) ;
break ;
2010-02-18 17:43:38 +00:00
}
}
2009-05-08 13:28:41 +00:00
// release reference to key
pKey - > Deref ( ) ;
2010-02-18 17:43:38 +00:00
}
2009-05-08 13:28:41 +00:00
void C4KeyboardInput : : UnregisterKeyBinding ( C4CustomKey * pUnregKey )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// find key in name map
KeyNameMap : : iterator in = KeysByName . find ( pUnregKey - > GetName ( ) . getData ( ) ) ;
if ( in = = KeysByName . end ( ) ) return ;
C4CustomKey * pKey = in - > second ;
// is this key in the map?
if ( pKey ! = pUnregKey )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// Other key is in the list: Just remove the callbacks
pKey - > KillCallbacks ( pUnregKey ) ;
return ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// this key is in the list: Replace by a duplicate...
C4CustomKey * pNewKey = new C4CustomKey ( * pUnregKey , true ) ;
// ...without the own callbacks
pNewKey - > KillCallbacks ( pUnregKey ) ;
// and replace current key by duplicate
UnregisterKey ( pUnregKey - > GetName ( ) ) ;
RegisterKey ( pNewKey ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
2010-02-23 16:53:38 +00:00
bool C4KeyboardInput : : DoInput ( const C4KeyCodeEx & InKey , C4KeyEventType InEvent , DWORD InScope , int32_t iStrength )
2010-03-28 18:58:01 +00:00
{
2009-05-28 00:14:54 +00:00
// store last-key-info
2010-02-23 16:53:38 +00:00
LastKeyExtraData . iStrength = ( iStrength > = 0 ) ? iStrength : ( ( InEvent ! = KEYEV_Up ) * 100 ) ;
2016-01-17 03:06:19 +00:00
LastKeyExtraData . game_x = LastKeyExtraData . game_y = LastKeyExtraData . vp_x = LastKeyExtraData . vp_y = C4KeyEventData : : KeyPos_None ;
2009-05-08 13:28:41 +00:00
// check all key events generated by this key: First the keycode itself, then any more generic key events like KEY_Any
const int32_t iKeyRangeMax = 5 ;
int32_t iKeyRangeCnt = 0 , j ;
2010-02-22 23:35:06 +00:00
C4KeyCode FallbackKeys [ iKeyRangeMax ] ;
FallbackKeys [ iKeyRangeCnt + + ] = InKey . Key ;
2009-05-08 13:28:41 +00:00
if ( Key_IsGamepadButton ( InKey . Key ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// "any gamepad button"-event
2016-02-20 21:25:07 +00:00
FallbackKeys [ iKeyRangeCnt + + ] = KEY_Gamepad ( KEY_CONTROLLER_AnyButton ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
else if ( Key_IsGamepadAxis ( InKey . Key ) )
2010-03-28 18:58:01 +00:00
{
2016-02-17 19:58:12 +00:00
// TODO: do we need "any axis" events?
2010-03-28 18:58:01 +00:00
}
2010-02-22 23:35:06 +00:00
if ( InKey . Key ! = KEY_Any ) FallbackKeys [ iKeyRangeCnt + + ] = KEY_Any ;
// now get key ranges for fallback chain
std : : pair < KeyCodeMap : : iterator , KeyCodeMap : : iterator > KeyRanges [ iKeyRangeMax ] ;
2009-05-08 13:28:41 +00:00
assert ( iKeyRangeCnt < = iKeyRangeMax ) ;
2010-02-22 23:35:06 +00:00
for ( int32_t i = 0 ; i < iKeyRangeCnt ; + + i )
{
KeyRanges [ i ] = KeysByCode . equal_range ( FallbackKeys [ i ] ) ;
}
2009-05-08 13:28:41 +00:00
// check all assigned keys
// exec from highest to lowest priority
unsigned int uiLastPrio = C4CustomKey : : PRIO_MoreThanMax ;
2010-03-28 18:58:01 +00:00
for ( ; ; )
{
2009-05-08 13:28:41 +00:00
KeyCodeMap : : const_iterator i ;
// get priority to exec
unsigned int uiExecPrio = C4CustomKey : : PRIO_None , uiCurr ;
for ( j = 0 ; j < iKeyRangeCnt ; + + j )
for ( i = KeyRanges [ j ] . first ; i ! = KeyRanges [ j ] . second ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
uiCurr = i - > second - > GetPriority ( ) ;
if ( uiCurr > uiExecPrio & & uiCurr < uiLastPrio ) uiExecPrio = uiCurr ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// nothing with correct priority set left?
if ( uiExecPrio = = C4CustomKey : : PRIO_None ) break ;
// exec all of this priority
for ( j = 0 ; j < iKeyRangeCnt ; + + j )
for ( i = KeyRanges [ j ] . first ; i ! = KeyRanges [ j ] . second ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4CustomKey * pKey = i - > second ;
assert ( pKey ) ;
// check priority
if ( pKey - > GetPriority ( ) = = uiExecPrio )
2016-01-09 04:17:11 +00:00
// check scope and modifier
// (not on release of a key that has been down, because a key release might happen with a different modifier or in different scope than its pressing!)
if ( ( InEvent = = KEYEV_Up & & pKey - > IsDown ( ) )
| | ( ( pKey - > GetScope ( ) & InScope ) & & pKey - > IsCodeMatched ( C4KeyCodeEx ( FallbackKeys [ j ] , C4KeyShiftState ( InKey . dwShift ) ) ) ) )
// exec it
if ( pKey - > Execute ( InEvent , InKey ) )
2010-02-18 17:43:38 +00:00
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// nothing found in this priority: exec next
uiLastPrio = uiExecPrio ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// no key matched or all returned false in Execute: Not processed
return false ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
void C4KeyboardInput : : CompileFunc ( StdCompiler * pComp )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// compile all keys that are already defined
// no definition of new keys with current compiler...
pComp - > Name ( " Keys " ) ;
try
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
for ( KeyNameMap : : const_iterator i = KeysByName . begin ( ) ; i ! = KeysByName . end ( ) ; + + i )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// naming done in C4CustomKey, because default is determined by key only
C4CustomKey : : CodeList OldCodes = i - > second - > GetCodes ( ) ;
pComp - > Value ( * i - > second ) ;
// resort in secondary map if key changed
2017-03-11 14:05:41 +00:00
if ( pComp - > isDeserializer ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
const C4CustomKey : : CodeList & rNewCodes = i - > second - > GetCodes ( ) ;
if ( ! ( OldCodes = = rNewCodes ) ) UpdateKeyCodes ( i - > second , OldCodes , rNewCodes ) ;
}
2010-03-27 16:05:02 +00:00
}
2010-03-28 18:58:01 +00:00
}
catch ( StdCompiler : : Exception * pEx )
{
2009-05-08 13:28:41 +00:00
pComp - > NameEnd ( true ) ;
throw pEx ;
}
2010-03-28 18:58:01 +00:00
pComp - > NameEnd ( ) ;
}
2009-05-08 13:28:41 +00:00
bool C4KeyboardInput : : LoadCustomConfig ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
// load from INI file (2do: load from registry)
C4Group GrpExtra ;
if ( ! GrpExtra . Open ( C4CFN_Extra ) ) return false ;
StdBuf sFileContents ;
2011-03-05 01:44:26 +00:00
if ( ! GrpExtra . LoadEntry ( C4CFN_KeyConfig , & sFileContents ) ) return false ;
2009-05-08 13:28:41 +00:00
StdStrBuf sFileContentsString ( ( const char * ) sFileContents . getData ( ) ) ;
2010-03-28 18:58:01 +00:00
if ( ! CompileFromBuf_LogWarn < StdCompilerINIRead > ( * this , sFileContentsString , " Custom keys from " C4CFN_Extra DirSep C4CFN_KeyConfig ) )
2009-05-08 13:28:41 +00:00
return false ;
LogF ( LoadResStr ( " IDS_PRC_LOADEDKEYCONF " ) , C4CFN_Extra DirSep C4CFN_KeyConfig ) ;
return true ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4CustomKey * C4KeyboardInput : : GetKeyByName ( const char * szKeyName )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
KeyNameMap : : const_iterator i = KeysByName . find ( szKeyName ) ;
2016-11-02 23:58:02 +00:00
if ( i = = KeysByName . end ( ) ) return nullptr ; else return ( * i ) . second ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
StdStrBuf C4KeyboardInput : : GetKeyCodeNameByKeyName ( const char * szKeyName , bool fShort , int32_t iIndex )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4CustomKey * pKey = GetKeyByName ( szKeyName ) ;
if ( pKey )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
const C4CustomKey : : CodeList & codes = pKey - > GetCodes ( ) ;
if ( ( size_t ) iIndex < codes . size ( ) )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
C4KeyCodeEx code = codes [ iIndex ] ;
return code . ToString ( true , fShort ) ;
}
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
// Error
return StdStrBuf ( ) ;
2010-03-28 18:58:01 +00:00
}
2009-05-08 13:28:41 +00:00
C4KeyboardInput & C4KeyboardInput_Init ( )
2010-03-28 18:58:01 +00:00
{
2009-05-08 13:28:41 +00:00
static C4KeyboardInput keyinp ;
return keyinp ;
2010-03-28 18:58:01 +00:00
}