# pragma region License
/*
License ( OLC - 3 )
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
Copyright 2024 Joshua Sigona < sigonasr2 @ gmail . com >
Redistribution and use in source and binary forms , with or without modification ,
are permitted provided that the following conditions are met :
1. Redistributions or derivations of source code must retain the above copyright
notice , this list of conditions and the following disclaimer .
2. Redistributions or derivative works in binary form must reproduce the above
copyright notice . This list of conditions and the following disclaimer must be
reproduced in the documentation and / or other materials provided with the distribution .
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without specific
prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS " AND ANY
EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED
TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
Portions of this software are copyright © 2024 The FreeType
Project ( www . freetype . org ) . Please see LICENSE_FT . txt for more information .
All rights reserved .
*/
# pragma endregion
# include "Key.h"
# include "DEFINES.h"
# include "AdventuresInLestoria.h"
# include "olcPGEX_Gamepad.h"
# include "Menu.h"
# include "GameSettings.h"
INCLUDE_game
INCLUDE_GFX
bool Input : : usingGamepad ;
safemap < std : : string , InputGroup * > InputGroup : : menuNamesToInputGroups ;
std : : vector < std : : string > InputGroup : : menuInputGroups ;
std : : vector < std : : string > InputGroup : : gameplayInputGroups ;
Input : : Input ( InputType type , int key )
: type ( type ) , key ( key ) { }
bool Input : : Pressed ( ) {
if ( ! game - > IsFocused ( ) ) return false ;
bool inputPressed = false ;
switch ( type ) {
case KEY : {
inputPressed = game - > GetKey ( Key ( key ) ) . bPressed ;
} break ;
case MOUSE : {
inputPressed = game - > GetMouse ( key ) . bPressed ;
} break ;
case CONTROLLER : {
for ( GamePad * gamepad : GamePad : : getGamepads ( ) ) {
if ( gamepad - > stillConnected & & gamepad - > getButton ( static_cast < GPButtons > ( key ) ) . bPressed ) inputPressed = true ;
}
} break ;
case ANALOG : {
//An analog input can never be "pressed". No-op.
} break ;
default : {
ERR ( " Invalid Control Scheme detected! We shouldn't be here!! Type is " < < type ) ;
}
}
if ( inputPressed ) {
usingGamepad = type = = CONTROLLER ;
return true ;
}
return false ;
}
bool Input : : Held ( ) {
if ( ! game - > IsFocused ( ) ) return false ;
bool inputHeld = false ;
switch ( type ) {
case KEY : {
inputHeld = game - > GetKey ( Key ( key ) ) . bHeld ;
} break ;
case MOUSE : {
inputHeld = game - > GetMouse ( key ) . bHeld ;
} break ;
case CONTROLLER : {
for ( GamePad * gamepad : GamePad : : getGamepads ( ) ) {
if ( gamepad - > stillConnected & & gamepad - > getButton ( static_cast < GPButtons > ( key ) ) . bHeld ) inputHeld = true ;
}
} break ;
case ANALOG : {
//An analog input can never be "held". No-op.
} break ;
default : {
ERR ( " Invalid Control Scheme detected! We shouldn't be here!! Type is " < < type ) ;
}
}
if ( inputHeld ) {
usingGamepad = type = = CONTROLLER ;
return true ;
}
return false ;
}
bool Input : : Released ( ) {
if ( ! game - > IsFocused ( ) ) return false ;
bool inputReleased = false ;
switch ( type ) {
case KEY : {
inputReleased = game - > GetKey ( Key ( key ) ) . bReleased ;
} break ;
case MOUSE : {
inputReleased = game - > GetMouse ( key ) . bReleased ;
} break ;
case CONTROLLER : {
for ( GamePad * gamepad : GamePad : : getGamepads ( ) ) {
if ( gamepad - > stillConnected & & gamepad - > getButton ( static_cast < GPButtons > ( key ) ) . bReleased ) inputReleased = true ;
}
} break ;
case ANALOG : {
//An analog input can never be "released". No-op.
} break ;
default : {
ERR ( " Invalid Control Scheme detected! We shouldn't be here!! Type is " < < type ) ;
}
}
if ( inputReleased ) {
usingGamepad = type = = CONTROLLER ;
return true ;
}
return false ;
}
float Input : : Analog ( ) {
if ( ! game - > IsFocused ( ) ) return false ;
switch ( type ) {
case ANALOG : {
for ( GamePad * gamepad : GamePad : : getGamepads ( ) ) {
if ( gamepad - > stillConnected ) {
float axisVal = gamepad - > getAxis ( static_cast < GPAxes > ( key ) ) ;
if ( axisVal ! = 0.f ) {
usingGamepad = true ;
return axisVal ;
}
}
}
} break ;
case KEY :
case MOUSE :
case CONTROLLER : {
//Doesn't return analog inputs. No-op.
} break ;
default : {
ERR ( " Invalid Control Scheme detected for analog controls! We shouldn't be here!! Type is " < < type ) ;
}
}
return 0.f ;
}
std : : string Input : : GetDisplayName ( ) const {
return GenericKey : : keyLiteral . at ( { type , key } ) . displayName ;
}
const std : : string Input : : str ( ) const {
std : : string outputStr = " " ;
switch ( type ) {
case KEY : {
outputStr = std : : format ( " [Type:KEY,Key:{}] " , GetDisplayName ( ) ) ;
} break ;
case MOUSE : {
outputStr = std : : format ( " [Type:MOUSE,Key:{}] " , GetDisplayName ( ) ) ;
} break ;
case CONTROLLER : {
outputStr = std : : format ( " [Type:CONTROLLER,Key:{}] " , GetDisplayName ( ) ) ;
} break ;
case ANALOG : {
outputStr = std : : format ( " [Type:ANALOG,Key:{}] " , GetDisplayName ( ) ) ;
} break ;
default : {
ERR ( std : : format ( " WARNING! Unhandled input type: {} " , int ( type ) ) )
}
}
return outputStr ;
}
InputGroup : : InputGroup ( ) { }
void InputGroup : : AddKeybind ( Input bind ) {
keys . insert ( bind ) ;
keyOrder . push_back ( bind ) ;
}
void InputGroup : : RemoveKeybind ( Input bind ) {
size_t erased = keys . erase ( bind ) ;
erased + = std : : erase ( keyOrder , bind ) ;
if ( erased ! = 2 ) ERR ( std : : format ( " WARNING! Could not remove keybind {} " , bind . str ( ) ) ) ;
}
const bool InputGroup : : Pressed ( ) const {
for ( Input input : keys ) {
if ( input . Pressed ( ) ) return true ;
}
return false ;
}
const bool InputGroup : : PressedDAS ( ) {
for ( Input input : keys ) {
if ( input . Pressed ( ) ) {
if ( initialHoldDownTime = = 0.f ) {
initialHoldDownTime = " Interface.InitialScrollDelay " _F ;
}
return true ;
} else
if ( input . Held ( ) & & initialHoldDownTime > 0.f ) {
initialHoldDownTime - = game - > GetElapsedTime ( ) ;
if ( initialHoldDownTime < = 0.f ) {
holdDownTime = " Interface.ScrollDelay " _F ;
return true ;
}
} else
if ( input . Held ( ) & & holdDownTime > 0.f ) {
holdDownTime - = game - > GetElapsedTime ( ) ;
if ( holdDownTime < = 0.f ) {
holdDownTime = " Interface.ScrollDelay " _F ;
return true ;
}
}
}
return false ;
}
const bool InputGroup : : Held ( ) const {
for ( Input input : keys ) {
if ( input . Held ( ) ) return true ;
}
return false ;
}
const bool InputGroup : : Released ( ) {
for ( Input input : keys ) {
if ( input . Released ( ) ) {
initialHoldDownTime = holdDownTime = 0.f ; //Reset hold times if we release the key.
return true ;
}
}
return false ;
}
const float InputGroup : : Analog ( ) const {
for ( Input input : keys ) {
float analogVal = input . Analog ( ) ;
if ( analogVal ! = 0.f ) return analogVal ;
}
return 0.f ;
}
const float InputGroup : : AnalogDAS ( const float threshold ) {
for ( Input input : keys ) {
float analogVal = input . Analog ( ) ;
if ( abs ( analogVal ) > = threshold & & initialHoldDownTime = = 0.f ) {
initialHoldDownTime = " Interface.InitialScrollDelay " _F ;
return analogVal ;
} else
if ( abs ( analogVal ) > = threshold & & initialHoldDownTime > 0.f ) {
initialHoldDownTime - = game - > GetElapsedTime ( ) ;
if ( initialHoldDownTime < = 0.f ) {
holdDownTime = " Interface.ScrollDelay " _F ;
return analogVal ;
}
return 0.f ;
} else
if ( abs ( analogVal ) > = threshold & & holdDownTime > 0.f ) {
holdDownTime - = game - > GetElapsedTime ( ) ;
if ( holdDownTime < = 0.f ) {
holdDownTime = " Interface.ScrollDelay " _F ;
return analogVal ;
}
return 0.f ;
}
}
initialHoldDownTime = holdDownTime = 0.f ;
return 0.f ;
}
std : : string InputGroup : : GetDisplayName ( ) {
std : : string combinationDisplay = " " ;
for ( Input input : keys ) {
if ( combinationDisplay . length ( ) > 0 ) {
combinationDisplay + = " , " ;
}
combinationDisplay + = input . GetDisplayName ( ) ;
}
return combinationDisplay ;
}
void InputGroup : : DrawInput ( const std : : variant < AiL * const , TileTransformedView * const > renderer , const vf2d pos , const std : : string_view displayText , const uint8_t alpha , InputType type ) const {
std : : optional < Input > primaryKey ;
switch ( type ) {
case CONTROLLER : primaryKey = GetPrimaryKey ( CONTROLLER ) ; break ;
case MOUSE : primaryKey = GetPrimaryKey ( MOUSE ) ; break ;
default : primaryKey = GetPrimaryKey ( KEY ) ; break ;
}
vf2d buttonImgSize { } ;
std : : vector < std : : variant < Decal * , std : : string > > buttonImgs ;
if ( type ! = CONTROLLER & & type ! = MOUSE ) {
for ( const Input & input : keyOrder ) {
if ( input . GetType ( ) = = MOUSE ) {
if ( input . HasIcon ( ) ) {
buttonImgSize . x + = input . GetIcon ( ) . Sprite ( ) - > width + " Interface.InputHelperSpacing " _F ;
buttonImgSize . y = std : : max ( buttonImgSize . y , float ( input . GetIcon ( ) . Sprite ( ) - > height ) ) ;
buttonImgs . push_back ( input . GetIcon ( ) . Decal ( ) ) ;
} else {
buttonImgSize . x + = game - > GetTextSizeProp ( input . GetDisplayName ( ) ) . x + " Interface.InputHelperSpacing " _F ;
buttonImgSize . y = std : : max ( buttonImgSize . y , float ( game - > GetTextSizeProp ( input . GetDisplayName ( ) ) . y ) + " Interface.InputHelperSpacing " _F ) ;
buttonImgs . push_back ( input . GetDisplayName ( ) ) ;
}
}
}
}
if ( primaryKey . has_value ( ) ) {
if ( primaryKey . value ( ) . HasIcon ( ) ) {
buttonImgSize . x + = primaryKey . value ( ) . GetIcon ( ) . Sprite ( ) - > width + " Interface.InputHelperSpacing " _F ;
buttonImgSize . y = std : : max ( buttonImgSize . y , float ( primaryKey . value ( ) . GetIcon ( ) . Sprite ( ) - > height ) ) ;
buttonImgs . push_back ( primaryKey . value ( ) . GetIcon ( ) . Decal ( ) ) ;
} else {
buttonImgSize . x + = game - > GetTextSizeProp ( primaryKey . value ( ) . GetDisplayName ( ) ) . x + " Interface.InputHelperSpacing " _F ;
buttonImgSize . y = std : : max ( buttonImgSize . y , float ( game - > GetTextSizeProp ( primaryKey . value ( ) . GetDisplayName ( ) ) . y ) + " Interface.InputHelperSpacing " _F ) ;
buttonImgs . push_back ( primaryKey . value ( ) . GetDisplayName ( ) ) ;
}
}
vf2d descriptionTextSize = game - > GetTextSizeProp ( displayText ) ;
vf2d offset = - ( ( buttonImgSize + descriptionTextSize ) / 2.f ) ;
for ( auto & button : buttonImgs ) {
if ( std : : holds_alternative < Decal * > ( button ) ) {
Decal * img = std : : get < Decal * > ( button ) ;
# pragma region Render Macro
# define Render(rendererType) \
std : : get < rendererType * const > ( renderer ) - > DrawDecal ( pos + offset - vf2d { 0.f , 2.f } , img , { 1.f , 1.f } , { 255 , 255 , 255 , alpha } ) ;
# pragma endregion
if ( std : : holds_alternative < AiL * const > ( renderer ) ) {
Render ( AiL ) ;
} else
if ( std : : holds_alternative < TileTransformedView * const > ( renderer ) ) {
Render ( TileTransformedView ) ;
}
offset . x + = img - > sprite - > width + " Interface.InputHelperSpacing " _I ;
} else
if ( std : : holds_alternative < std : : string > ( button ) ) {
std : : string label = std : : get < std : : string > ( button ) ;
vf2d textSize = game - > GetTextSizeProp ( label ) ;
Pixel buttonBackCol = " Interface.InputButtonBackCol " _Pixel ;
Pixel buttonTextCol = " Interface.InputButtonTextCol " _Pixel ;
buttonBackCol . a = alpha ;
buttonTextCol . a = alpha ;
# pragma region Render Macro
# define Render(rendererType) \
std : : get < rendererType * const > ( renderer ) - > FillRectDecal ( pos + offset + vf2d { - 2.f , 0.f } , vf2d { textSize . x + 4 , textSize . y } , buttonBackCol ) ; \
std : : get < rendererType * const > ( renderer ) - > FillRectDecal ( pos + offset + vf2d { - 1.f , - 1.f } , vf2d { textSize . x + 2 , textSize . y } , buttonBackCol ) ; \
std : : get < rendererType * const > ( renderer ) - > FillRectDecal ( pos + offset + vf2d { - 1.f , 0.f } , vf2d { textSize . x + 2 , textSize . y + 1.f } , buttonBackCol ) ; \
std : : get < rendererType * const > ( renderer ) - > DrawStringPropDecal ( pos + offset + vf2d { 0.f , 0.f } , label , buttonTextCol ) ;
# pragma endregion
if ( std : : holds_alternative < AiL * const > ( renderer ) ) {
Render ( AiL ) ;
} else
if ( std : : holds_alternative < TileTransformedView * const > ( renderer ) ) {
Render ( TileTransformedView ) ;
}
offset . x + = textSize . x + " Interface.InputHelperSpacing " _I ;
} else [[unlikely]] ERR ( " WARNING! Hit a state where no data is inside of the button! THIS SHOULD NOT BE HAPPENING! " ) ;
}
game - > view . DrawShadowStringPropDecal ( pos + offset , displayText , { 255 , 255 , 255 , alpha } , { 0 , 0 , 0 , alpha } ) ;
}
void InputGroup : : DrawInput ( const std : : variant < AiL * const , TileTransformedView * const > renderer , const vf2d pos , const std : : string_view displayText , const uint8_t alpha ) const {
InputType primaryType ;
if ( Input : : UsingGamepad ( ) ) primaryType = CONTROLLER ;
else if ( Menu : : UsingMouseNavigation ( ) ) primaryType = MOUSE ;
else primaryType = KEY ;
DrawInput ( renderer , pos , displayText , alpha , primaryType ) ;
}
const bool Input : : HasIcon ( ) const {
return GenericKey : : keyLiteral . at ( { type , key } ) . iconName . length ( ) > 0 ;
}
const Renderable & Input : : GetIcon ( ) const {
return GFX . at ( GenericKey : : keyLiteral . at ( { type , key } ) . iconName ) ;
}
# undef END
std : : map < std : : pair < InputType , int > , GenericKey : : KeyInfo > GenericKey : : keyLiteral = {
{ { KEY , NONE } , { " " } } ,
{ { KEY , A } , { " A " } } ,
{ { KEY , B } , { " B " } } ,
{ { KEY , C } , { " C " } } ,
{ { KEY , D } , { " D " } } ,
{ { KEY , E } , { " E " } } ,
{ { KEY , F } , { " F " } } ,
{ { KEY , G } , { " G " } } ,
{ { KEY , H } , { " H " } } ,
{ { KEY , I } , { " I " } } ,
{ { KEY , J } , { " J " } } ,
{ { KEY , K } , { " K " } } ,
{ { KEY , L } , { " L " } } ,
{ { KEY , M } , { " M " } } ,
{ { KEY , N } , { " N " } } ,
{ { KEY , O } , { " O " } } ,
{ { KEY , P } , { " P " } } ,
{ { KEY , Q } , { " Q " } } ,
{ { KEY , R } , { " R " } } ,
{ { KEY , S } , { " S " } } ,
{ { KEY , T } , { " T " } } ,
{ { KEY , U } , { " U " } } ,
{ { KEY , V } , { " V " } } ,
{ { KEY , W } , { " W " } } ,
{ { KEY , X } , { " X " } } ,
{ { KEY , Y } , { " Y " } } ,
{ { KEY , Z } , { " Z " } } ,
{ { KEY , K0 } , { " 0 " } } ,
{ { KEY , K1 } , { " 1 " } } ,
{ { KEY , K2 } , { " 2 " } } ,
{ { KEY , K3 } , { " 3 " } } ,
{ { KEY , K4 } , { " 4 " } } ,
{ { KEY , K5 } , { " 5 " } } ,
{ { KEY , K6 } , { " 6 " } } ,
{ { KEY , K7 } , { " 7 " } } ,
{ { KEY , K8 } , { " 8 " } } ,
{ { KEY , K9 } , { " 9 " } } ,
{ { KEY , F1 } , { " F1 " } } ,
{ { KEY , F2 } , { " F2 " } } ,
{ { KEY , F3 } , { " F3 " } } ,
{ { KEY , F4 } , { " F4 " } } ,
{ { KEY , F5 } , { " F5 " } } ,
{ { KEY , F6 } , { " F6 " } } ,
{ { KEY , F7 } , { " F7 " } } ,
{ { KEY , F8 } , { " F8 " } } ,
{ { KEY , F9 } , { " F9 " } } ,
{ { KEY , F10 } , { " F10 " } } ,
{ { KEY , F11 } , { " F11 " } } ,
{ { KEY , F12 } , { " F12 " } } ,
{ { KEY , UP } , { " UP " } } ,
{ { KEY , DOWN } , { " DOWN " } } ,
{ { KEY , LEFT } , { " LEFT " } } ,
{ { KEY , RIGHT } , { " RIGHT " } } ,
{ { KEY , SPACE } , { " SPACE " } } ,
{ { KEY , TAB } , { " TAB " } } ,
{ { KEY , SHIFT } , { " SHIFT " } } ,
{ { KEY , CTRL } , { " CTRL " } } ,
{ { KEY , INS } , { " INS " } } ,
{ { KEY , DEL } , { " DEL " } } ,
{ { KEY , HOME } , { " HOME " } } ,
{ { KEY , END } , { " END " } } ,
{ { KEY , PGUP } , { " PGUP " } } ,
{ { KEY , PGDN } , { " PGDN " } } ,
{ { KEY , BACK } , { " BACK " } } ,
{ { KEY , ESCAPE } , { " ESC " } } ,
{ { KEY , RETURN } , { " ENTER " } } ,
{ { KEY , ENTER } , { " ENTER " } } ,
{ { KEY , Key : : PAUSE } , { " PAUSE " } } ,
{ { KEY , SCROLL } , { " SCR LK " } } ,
{ { KEY , NP0 } , { " NP0 " } } ,
{ { KEY , NP1 } , { " NP1 " } } ,
{ { KEY , NP2 } , { " NP2 " } } ,
{ { KEY , NP3 } , { " NP3 " } } ,
{ { KEY , NP4 } , { " NP4 " } } ,
{ { KEY , NP5 } , { " NP5 " } } ,
{ { KEY , NP6 } , { " NP6 " } } ,
{ { KEY , NP7 } , { " NP7 " } } ,
{ { KEY , NP8 } , { " NP8 " } } ,
{ { KEY , NP9 } , { " NP9 " } } ,
{ { KEY , NP_MUL } , { " NP* " } } ,
{ { KEY , NP_DIV } , { " NP/ " } } ,
{ { KEY , NP_ADD } , { " NP+ " } } ,
{ { KEY , NP_SUB } , { " NP- " } } ,
{ { KEY , NP_DECIMAL } , { " NP. " } } ,
{ { KEY , PERIOD } , { " . " } } ,
{ { KEY , EQUALS } , { " = " } } ,
{ { KEY , COMMA } , { " ,{ " } } ,
{ { KEY , MINUS } , { " - " } } ,
{ { KEY , OEM_1 } , { " ; " } } ,
{ { KEY , OEM_2 } , { " / " } } ,
{ { KEY , OEM_3 } , { " ~ " } } ,
{ { KEY , OEM_4 } , { " [ " } } ,
{ { KEY , OEM_5 } , { " \\ " } } ,
{ { KEY , OEM_6 } , { " ] " } } ,
{ { KEY , OEM_7 } , { " \" " } } ,
{ { KEY , OEM_8 } , { " \\ " } } ,
{ { KEY , CAPS_LOCK } , { " CAP LK " } } ,
{ { KEY , olc : : ENUM_END } , { " " } } ,
{ { KEY , SHOULDER } , { " Q-E " , " themes/button_qe.png " } } ,
{ { KEY , ARROWS } , { " Arrow Keys " , " themes/button_arrows.png " } } ,
{ { MOUSE , Mouse : : LEFT } , { " L.MOUSE " , " themes/lmb.png " } } ,
{ { MOUSE , Mouse : : RIGHT } , { " R.MOUSE " , " themes/rmb.png " } } ,
{ { MOUSE , Mouse : : MIDDLE } , { " M.MOUSE " , " themes/mmb.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : FACE_D ) } , { " A/X " , " themes/button_d.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : FACE_L ) } , { " X/Square " , " themes/button_l.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : FACE_R ) } , { " B/Circle " , " themes/button_r.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : FACE_U ) } , { " Y/Triangle " , " themes/button_u.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : L1 ) } , { " L1 " , " themes/button_l1.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : L2 ) } , { " L2 " , " themes/button_l2.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : L3 ) } , { " L3 " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : R1 ) } , { " R1 " , " themes/button_r1.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : R2 ) } , { " R2 " , " themes/button_r2.png " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : R3 ) } , { " R3 " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : SELECT ) } , { " SELECT " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : START ) } , { " START " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : DPAD_L ) } , { " LEFT " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : DPAD_R ) } , { " RIGHT " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : DPAD_U ) } , { " UP " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : DPAD_D ) } , { " DOWN " } } ,
{ { CONTROLLER , static_cast < int > ( GPButtons : : SHOULDER ) } , { " L1-R1 " , " themes/button_r1l1.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : LY ) } , { " Up/Down " , " themes/button_analogstick_vert.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : RY ) } , { " Up/Down " , " themes/button_analogstick_vert.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : LX ) } , { " Right/Left " , " themes/button_analogstick_horz.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : RX ) } , { " Right/Left " , " themes/button_analogstick_horz.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : TL ) } , { " Left Trigger " , " themes/button_l2.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : TR ) } , { " Right Trigger " , " themes/button_r2.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : DX ) } , { " Right/Left " , " themes/button_analogstick_horz.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : DY ) } , { " Up/Down " , " themes/button_analogstick_vert.png " } } ,
{ { ANALOG , static_cast < int > ( GPAxes : : ALL ) } , { " Analog Stick " , " themes/button_analogstick.png " } } ,
} ;
void Input : : SetUsingGamepad ( const bool usingGamepad ) {
Input : : usingGamepad = usingGamepad ;
}
const bool Input : : UsingGamepad ( ) {
return usingGamepad ;
}
const bool Input : : AxesActive ( ) {
float xAxis = 0.f , yAxis = 0.f ;
for ( GamePad * gamepad : GamePad : : getGamepads ( ) ) {
if ( gamepad - > stillConnected ) {
if ( fabs ( gamepad - > getAxis ( GPAxes : : RX ) ) > 0.f ) {
xAxis = gamepad - > getAxis ( GPAxes : : RX ) ;
}
if ( fabs ( gamepad - > getAxis ( GPAxes : : RY ) ) > 0.f ) {
yAxis = gamepad - > getAxis ( GPAxes : : RY ) ;
}
if ( xAxis ! = 0.f | | yAxis ! = 0.f ) break ; //Found a controller, so we're good to break.
}
}
return xAxis ! = 0.f | | yAxis ! = 0.f ;
}
void Input : : StartVibration ( ) {
if ( ! GameSettings : : RumbleEnabled ( ) ) return ;
if ( UsingGamepad ( ) ) {
for ( GamePad * gamepad : GamePad : : getGamepads ( ) ) {
if ( gamepad - > stillConnected ) {
gamepad - > startVibration ( ) ;
}
}
}
}
void Input : : StopVibration ( ) {
for ( GamePad * gamepad : GamePad : : getGamepads ( ) ) {
if ( gamepad - > stillConnected ) {
gamepad - > stopVibration ( ) ;
}
}
}
const bool operator < ( const InputGroup & group1 , const InputGroup & group2 ) {
return & group1 < & group2 ;
}
const bool operator < ( const InputEngageGroup & group1 , const InputEngageGroup & group2 ) {
return & group1 < & group2 ;
}
const InputType Input : : GetType ( ) const {
return type ;
}
const std : : optional < Input > InputGroup : : GetPrimaryKey ( InputType type ) const {
if ( type = = ANALOG ) ERR ( " WARNING! Type cannot be ANALOG! Not supported! " ) ;
std : : optional < Input > result ;
if ( keyOrder . size ( ) > 0 ) {
auto it = std : : find_if ( keyOrder . begin ( ) , keyOrder . end ( ) , [ & ] ( const Input & input ) {
return input . GetType ( ) = = type
| | ( type = = CONTROLLER & & input . GetType ( ) = = ANALOG ) ;
} ) ;
if ( it ! = keyOrder . end ( ) ) return * it ;
}
return result ;
}
const bool operator = = ( const Input & input1 , const Input & input2 ) {
return input1 . type = = input2 . type & & input1 . key = = input2 . key ;
}
InputEngageGroup : : InputEngageGroup ( InputGroup & group , EngageType type , const bool labelVisible )
: group ( group ) , type ( type ) , labelVisible ( labelVisible ) { }
const InputEngageGroup : : EngageType InputEngageGroup : : GetEngageType ( ) const {
return type ;
}
InputGroup & InputEngageGroup : : GetGroup ( ) const {
return group ;
}
const InputEngageGroup InputEngageGroup : : operator = ( const InputEngageGroup & rhs ) {
return InputEngageGroup { rhs . group , rhs . type } ;
}
void InputGroup : : RemovePrimaryKeybind ( InputType type ) {
auto primaryInputIt = std : : find_if ( keyOrder . begin ( ) , keyOrder . end ( ) , [ & ] ( Input & input ) { return input . GetType ( ) = = type ; } ) ;
if ( primaryInputIt ! = keyOrder . end ( ) ) {
Input & primaryInput = * primaryInputIt ;
keys . erase ( primaryInput ) ;
keyOrder . erase ( primaryInputIt ) ;
} else ERR ( std : : format ( " WARNING! Could not find a valid primary input of type {}! THIS SHOULD NOT BE HAPPENING! " , int ( type ) ) ) ;
}
void InputGroup : : AddPrimaryKeybind ( Input key ) {
keys . insert ( key ) ;
keyOrder . insert ( keyOrder . begin ( ) , { key . GetType ( ) , key . key } ) ;
}
void InputGroup : : SetNewPrimaryKeybind ( Input key ) {
RemovePrimaryKeybind ( key . GetType ( ) ) ;
AddPrimaryKeybind ( key ) ;
}
void InputListener : : Update ( ) {
# pragma region New controller input binding listener
using A = Attribute ;
if ( Menu : : IsMenuOpen ( ) & & Menu : : stack . back ( ) = = Menu : : menus [ NEW_INPUT ] & & ! Menu : : menus [ NEW_INPUT ] - > B ( A : : IS_KEYBOARD ) ) { //We are requesting a brand new controller input.
if ( InputGroup : : menuNamesToInputGroups . count ( Menu : : menus [ NEW_INPUT ] - > S ( A : : KEYBIND ) ) ) {
for ( GamePad * gamepad : GamePad : : getGamepads ( ) ) {
for ( size_t button = 0 ; bool hasButton : gamepad - > availableButtons ) {
GPButtons releasedButton = olc : : GPButtons ( button ) ;
if ( gamepad - > getButton ( releasedButton ) . bReleased ) {
InputGroup : : menuNamesToInputGroups [ Menu : : menus [ NEW_INPUT ] - > S ( A : : KEYBIND ) ] - > SetNewPrimaryKeybind ( Input { CONTROLLER , int ( button ) } ) ;
for ( auto & [ menuType , menu ] : Menu : : menus ) {
menu - > helpDisplay . Initialize ( menu - > inputGroups ) ;
}
Menu : : alreadyClicked = true ;
Menu : : CloseMenu ( ) ;
return ;
}
button + + ;
}
}
}
}
# pragma endregion
}
const int Input : : GetKeyCode ( ) const {
return key ;
}
const bool InputEngageGroup : : GetLabelVisible ( ) const {
return labelVisible ;
}