2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "BlueprintGraphPrivatePCH.h"
2014-05-29 16:42:22 -04:00
# include "K2Node_InputKeyEvent.h"
2014-03-14 14:13:41 -04:00
# include "CompilerResultsLog.h"
# include "KismetCompiler.h"
2014-07-14 13:19:37 -04:00
# include "BlueprintNodeSpawner.h"
# include "EditorCategoryUtils.h"
2014-08-21 18:50:33 -04:00
# include "BlueprintEditorUtils.h"
# include "EdGraphSchema_K2.h"
2014-08-23 20:16:29 -04:00
# include "BlueprintActionDatabaseRegistrar.h"
2014-11-12 06:03:49 -05:00
# include "GraphEditorSettings.h"
2014-07-14 13:19:37 -04:00
# define LOCTEXT_NAMESPACE "UK2Node_InputKey"
2014-03-14 14:13:41 -04:00
2014-10-14 10:29:11 -04:00
UK2Node_InputKey : : UK2Node_InputKey ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
bConsumeInput = true ;
bOverrideParentBinding = true ;
2014-11-19 12:45:49 -05:00
# if PLATFORM_MAC && WITH_EDITOR
if ( IsTemplate ( ) )
{
UProperty * ControlProp = GetClass ( ) - > FindPropertyByName ( GET_MEMBER_NAME_CHECKED ( UK2Node_InputKey , bControl ) ) ;
UProperty * CommandProp = GetClass ( ) - > FindPropertyByName ( GET_MEMBER_NAME_CHECKED ( UK2Node_InputKey , bCommand ) ) ;
ControlProp - > SetMetaData ( TEXT ( " DisplayName " ) , TEXT ( " Command " ) ) ;
CommandProp - > SetMetaData ( TEXT ( " DisplayName " ) , TEXT ( " Control " ) ) ;
}
# endif
2014-03-14 14:13:41 -04:00
}
void UK2Node_InputKey : : PostLoad ( )
{
Super : : PostLoad ( ) ;
if ( GetLinkerUE4Version ( ) < VER_UE4_BLUEPRINT_INPUT_BINDING_OVERRIDES )
{
// Don't change existing behaviors
bOverrideParentBinding = false ;
}
}
2014-11-19 12:45:49 -05:00
void UK2Node_InputKey : : PostEditChangeProperty ( FPropertyChangedEvent & PropertyChangedEvent )
{
Super : : PostEditChangeProperty ( PropertyChangedEvent ) ;
CachedNodeTitle . Clear ( ) ;
CachedTooltip . Clear ( ) ;
}
2014-03-14 14:13:41 -04:00
void UK2Node_InputKey : : AllocateDefaultPins ( )
{
const UEdGraphSchema_K2 * K2Schema = GetDefault < UEdGraphSchema_K2 > ( ) ;
CreatePin ( EGPD_Output , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , TEXT ( " Pressed " ) ) ;
CreatePin ( EGPD_Output , K2Schema - > PC_Exec , TEXT ( " " ) , NULL , false , false , TEXT ( " Released " ) ) ;
Super : : AllocateDefaultPins ( ) ;
}
FLinearColor UK2Node_InputKey : : GetNodeTitleColor ( ) const
{
2014-05-20 19:00:53 -04:00
return GetDefault < UGraphEditorSettings > ( ) - > EventNodeTitleColor ;
2014-03-14 14:13:41 -04:00
}
FName UK2Node_InputKey : : GetModifierName ( ) const
{
2014-11-19 12:45:49 -05:00
FString ModName ;
bool bPlus = false ;
if ( bControl )
{
ModName + = TEXT ( " Ctrl " ) ;
bPlus = true ;
}
if ( bCommand )
{
if ( bPlus ) ModName + = TEXT ( " + " ) ;
ModName + = TEXT ( " Cmd " ) ;
bPlus = true ;
}
if ( bAlt )
{
if ( bPlus ) ModName + = TEXT ( " + " ) ;
ModName + = TEXT ( " Alt " ) ;
bPlus = true ;
}
if ( bShift )
{
if ( bPlus ) ModName + = TEXT ( " + " ) ;
ModName + = TEXT ( " Shift " ) ;
bPlus = true ;
}
2014-03-14 14:13:41 -04:00
2014-11-19 12:45:49 -05:00
return FName ( * ModName ) ;
2014-03-14 14:13:41 -04:00
}
FText UK2Node_InputKey : : GetModifierText ( ) const
{
# if PLATFORM_MAC
2014-11-19 12:45:49 -05:00
const FText CommandText = NSLOCTEXT ( " UK2Node_InputKey " , " KeyName_Control " , " Ctrl " ) ;
const FText ControlText = NSLOCTEXT ( " UK2Node_InputKey " , " KeyName_Command " , " Cmd " ) ;
2014-03-14 14:13:41 -04:00
# else
2014-11-19 12:45:49 -05:00
const FText ControlText = NSLOCTEXT ( " UK2Node_InputKey " , " KeyName_Control " , " Ctrl " ) ;
const FText CommandText = NSLOCTEXT ( " UK2Node_InputKey " , " KeyName_Command " , " Cmd " ) ;
2014-03-14 14:13:41 -04:00
# endif
2014-11-19 12:45:49 -05:00
const FText AltText = NSLOCTEXT ( " UK2Node_InputKey " , " KeyName_Alt " , " Alt " ) ;
const FText ShiftText = NSLOCTEXT ( " UK2Node_InputKey " , " KeyName_Shift " , " Shift " ) ;
const FText AppenderText = NSLOCTEXT ( " UK2Node_InputKey " , " ModAppender " , " + " ) ;
FFormatNamedArguments Args ;
int32 ModCount = 0 ;
if ( bControl )
{
Args . Add ( FString : : Printf ( TEXT ( " Mod%d " ) , + + ModCount ) , ControlText ) ;
}
if ( bCommand )
{
Args . Add ( FString : : Printf ( TEXT ( " Mod%d " ) , + + ModCount ) , CommandText ) ;
}
if ( bAlt )
{
Args . Add ( FString : : Printf ( TEXT ( " Mod%d " ) , + + ModCount ) , AltText ) ;
}
if ( bShift )
{
Args . Add ( FString : : Printf ( TEXT ( " Mod%d " ) , + + ModCount ) , ShiftText ) ;
}
for ( int32 i = 1 ; i < = 4 ; + + i )
2014-03-14 14:13:41 -04:00
{
2014-11-19 12:45:49 -05:00
if ( i > ModCount )
{
Args . Add ( FString : : Printf ( TEXT ( " Mod%d " ) , i ) , FText : : GetEmpty ( ) ) ;
}
Args . Add ( FString : : Printf ( TEXT ( " Appender%d " ) , i ) , ( i < ModCount ? AppenderText : FText : : GetEmpty ( ) ) ) ;
2014-07-21 13:10:16 -04:00
}
2014-03-14 14:13:41 -04:00
2014-11-19 12:45:49 -05:00
Args . Add ( TEXT ( " Key " ) , GetKeyText ( ) ) ;
return FText : : Format ( NSLOCTEXT ( " UK2Node_InputKey " , " NodeTitle " , " {Mod1}{Appender1}{Mod2}{Appender2}{Mod3}{Appender3}{Mod4} " ) , Args ) ;
2014-03-14 14:13:41 -04:00
}
FText UK2Node_InputKey : : GetKeyText ( ) const
{
return InputKey . GetDisplayName ( ) ;
}
2014-04-23 18:30:37 -04:00
FText UK2Node_InputKey : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
2014-03-14 14:13:41 -04:00
{
2014-11-19 12:45:49 -05:00
if ( bControl | | bAlt | | bShift | | bCommand )
2014-03-14 14:13:41 -04:00
{
2015-04-02 11:16:23 -04:00
if ( CachedNodeTitle . IsOutOfDate ( this ) )
2014-09-02 19:08:09 -04:00
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ModifierKey " ) , GetModifierText ( ) ) ;
Args . Add ( TEXT ( " Key " ) , GetKeyText ( ) ) ;
// FText::Format() is slow, so we cache this to save on performance
2015-04-02 11:16:23 -04:00
CachedNodeTitle . SetCachedText ( FText : : Format ( NSLOCTEXT ( " K2Node " , " InputKey_Name_WithModifiers " , " {ModifierKey} {Key} " ) , Args ) , this ) ;
2014-09-02 19:08:09 -04:00
}
return CachedNodeTitle ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-04-23 18:30:37 -04:00
return GetKeyText ( ) ;
}
}
2014-09-03 18:14:09 -04:00
FText UK2Node_InputKey : : GetTooltipText ( ) const
2014-03-14 14:13:41 -04:00
{
2015-04-02 11:16:23 -04:00
if ( CachedTooltip . IsOutOfDate ( this ) )
2014-03-14 14:13:41 -04:00
{
2014-09-03 18:17:44 -04:00
FText ModifierText = GetModifierText ( ) ;
FText KeyText = GetKeyText ( ) ;
2014-03-14 14:13:41 -04:00
2014-09-03 18:17:44 -04:00
// FText::Format() is slow, so we cache this to save on performance
if ( ! ModifierText . IsEmpty ( ) )
{
2015-04-02 11:16:23 -04:00
CachedTooltip . SetCachedText ( FText : : Format ( NSLOCTEXT ( " K2Node " , " InputKey_Tooltip_Modifiers " , " Events for when the {0} key is pressed or released while {1} is also held. " ) , KeyText , ModifierText ) , this ) ;
2014-09-03 18:17:44 -04:00
}
else
{
2015-04-02 11:16:23 -04:00
CachedTooltip . SetCachedText ( FText : : Format ( NSLOCTEXT ( " K2Node " , " InputKey_Tooltip " , " Events for when the {0} key is pressed or released. " ) , KeyText ) , this ) ;
2014-09-03 18:17:44 -04:00
}
}
return CachedTooltip ;
2014-03-14 14:13:41 -04:00
}
FName UK2Node_InputKey : : GetPaletteIcon ( FLinearColor & OutColor ) const
{
if ( InputKey . IsMouseButton ( ) )
{
return TEXT ( " GraphEditor.MouseEvent_16x " ) ;
}
else if ( InputKey . IsGamepadKey ( ) )
{
return TEXT ( " GraphEditor.PadEvent_16x " ) ;
}
else
{
return TEXT ( " GraphEditor.KeyEvent_16x " ) ;
}
}
2014-08-21 18:50:33 -04:00
bool UK2Node_InputKey : : IsCompatibleWithGraph ( UEdGraph const * Graph ) const
{
UBlueprint * Blueprint = FBlueprintEditorUtils : : FindBlueprintForGraph ( Graph ) ;
UEdGraphSchema_K2 const * K2Schema = Cast < UEdGraphSchema_K2 > ( Graph - > GetSchema ( ) ) ;
bool const bIsConstructionScript = ( K2Schema ! = nullptr ) ? K2Schema - > IsConstructionScript ( Graph ) : false ;
return ( Blueprint ! = nullptr ) & & Blueprint - > SupportsInputEvents ( ) & & ! bIsConstructionScript & & Super : : IsCompatibleWithGraph ( Graph ) ;
}
2014-03-14 14:13:41 -04:00
UEdGraphPin * UK2Node_InputKey : : GetPressedPin ( ) const
{
return FindPin ( TEXT ( " Pressed " ) ) ;
}
UEdGraphPin * UK2Node_InputKey : : GetReleasedPin ( ) const
{
return FindPin ( TEXT ( " Released " ) ) ;
}
void UK2Node_InputKey : : ValidateNodeDuringCompilation ( class FCompilerResultsLog & MessageLog ) const
{
Super : : ValidateNodeDuringCompilation ( MessageLog ) ;
if ( ! InputKey . IsValid ( ) )
{
MessageLog . Warning ( * FText : : Format ( NSLOCTEXT ( " KismetCompiler " , " Invalid_InputKey_Warning " , " InputKey Event specifies invalid FKey'{0}' for @@ " ) , FText : : FromString ( InputKey . ToString ( ) ) ) . ToString ( ) , this ) ;
}
2014-04-28 11:24:25 -04:00
else if ( InputKey . IsFloatAxis ( ) )
2014-03-14 14:13:41 -04:00
{
MessageLog . Warning ( * FText : : Format ( NSLOCTEXT ( " KismetCompiler " , " Axis_InputKey_Warning " , " InputKey Event specifies axis FKey'{0}' for @@ " ) , FText : : FromString ( InputKey . ToString ( ) ) ) . ToString ( ) , this ) ;
}
else if ( ! InputKey . IsBindableInBlueprints ( ) )
{
MessageLog . Warning ( * FText : : Format ( NSLOCTEXT ( " KismetCompiler " , " NotBindanble_InputKey_Warning " , " InputKey Event specifies FKey'{0}' that is not blueprint bindable for @@ " ) , FText : : FromString ( InputKey . ToString ( ) ) ) . ToString ( ) , this ) ;
}
}
void UK2Node_InputKey : : CreateInputKeyEvent ( FKismetCompilerContext & CompilerContext , UEdGraph * SourceGraph , UEdGraphPin * InputKeyPin , const EInputEvent KeyEvent )
{
if ( InputKeyPin - > LinkedTo . Num ( ) > 0 )
{
UK2Node_InputKeyEvent * InputKeyEvent = CompilerContext . SpawnIntermediateNode < UK2Node_InputKeyEvent > ( this , SourceGraph ) ;
const FName ModifierName = GetModifierName ( ) ;
if ( ModifierName ! = NAME_None )
{
InputKeyEvent - > CustomFunctionName = FName ( * FString : : Printf ( TEXT ( " InpActEvt_%s_%s_%s " ) , * ModifierName . ToString ( ) , * InputKey . ToString ( ) , * InputKeyEvent - > GetName ( ) ) ) ;
}
else
{
InputKeyEvent - > CustomFunctionName = FName ( * FString : : Printf ( TEXT ( " InpActEvt_%s_%s " ) , * InputKey . ToString ( ) , * InputKeyEvent - > GetName ( ) ) ) ;
}
InputKeyEvent - > InputChord . Key = InputKey ;
InputKeyEvent - > InputChord . bCtrl = bControl ;
InputKeyEvent - > InputChord . bAlt = bAlt ;
InputKeyEvent - > InputChord . bShift = bShift ;
2014-07-30 14:31:25 -04:00
InputKeyEvent - > InputChord . bCmd = bCommand ;
2014-03-14 14:13:41 -04:00
InputKeyEvent - > bConsumeInput = bConsumeInput ;
InputKeyEvent - > bExecuteWhenPaused = bExecuteWhenPaused ;
InputKeyEvent - > bOverrideParentBinding = bOverrideParentBinding ;
InputKeyEvent - > InputKeyEvent = KeyEvent ;
2015-02-06 09:41:28 -05:00
InputKeyEvent - > EventReference . SetExternalDelegateMember ( FName ( TEXT ( " InputActionHandlerDynamicSignature__DelegateSignature " ) ) ) ;
2014-03-14 14:13:41 -04:00
InputKeyEvent - > bInternalEvent = true ;
InputKeyEvent - > AllocateDefaultPins ( ) ;
// Move any exec links from the InputActionNode pin to the InputActionEvent node
UEdGraphPin * EventOutput = CompilerContext . GetSchema ( ) - > FindExecutionPin ( * InputKeyEvent , EGPD_Output ) ;
if ( EventOutput ! = NULL )
{
2014-04-23 17:45:37 -04:00
CompilerContext . MovePinLinksToIntermediate ( * InputKeyPin , * EventOutput ) ;
2014-03-14 14:13:41 -04:00
}
}
}
void UK2Node_InputKey : : ExpandNode ( FKismetCompilerContext & CompilerContext , UEdGraph * SourceGraph )
{
Super : : ExpandNode ( CompilerContext , SourceGraph ) ;
2014-10-17 06:37:11 -04:00
CreateInputKeyEvent ( CompilerContext , SourceGraph , GetPressedPin ( ) , IE_Pressed ) ;
CreateInputKeyEvent ( CompilerContext , SourceGraph , GetReleasedPin ( ) , IE_Released ) ;
2014-07-14 13:19:37 -04:00
}
2014-08-23 20:16:29 -04:00
void UK2Node_InputKey : : GetMenuActions ( FBlueprintActionDatabaseRegistrar & ActionRegistrar ) const
2014-07-14 13:19:37 -04:00
{
TArray < FKey > AllKeys ;
EKeys : : GetAllKeys ( AllKeys ) ;
2014-09-10 17:09:26 -04:00
auto CustomizeInputNodeLambda = [ ] ( UEdGraphNode * NewNode , bool bIsTemplateNode , FKey Key )
{
UK2Node_InputKey * InputNode = CastChecked < UK2Node_InputKey > ( NewNode ) ;
InputNode - > InputKey = Key ;
} ;
2014-09-17 17:07:37 -04:00
// actions get registered under specific object-keys; the idea is that
// actions might have to be updated (or deleted) if their object-key is
// mutated (or removed)... here we use the node's class (so if the node
// type disappears, then the action should go with it)
UClass * ActionKey = GetClass ( ) ;
2014-07-14 13:19:37 -04:00
for ( FKey const Key : AllKeys )
{
// these will be handled by UK2Node_GetInputAxisKeyValue and UK2Node_GetInputVectorAxisValue respectively
if ( ! Key . IsBindableInBlueprints ( ) | | Key . IsFloatAxis ( ) | | Key . IsVectorAxis ( ) )
{
continue ;
}
2014-09-10 17:09:26 -04:00
// to keep from needlessly instantiating a UBlueprintNodeSpawner, first
// check to make sure that the registrar is looking for actions of this type
// (could be regenerating actions for a specific asset, and therefore the
// registrar would only accept actions corresponding to that asset)
if ( ! ActionRegistrar . IsOpenForRegistration ( ActionKey ) )
{
continue ;
}
2014-07-14 13:19:37 -04:00
UBlueprintNodeSpawner * NodeSpawner = UBlueprintNodeSpawner : : Create ( GetClass ( ) ) ;
check ( NodeSpawner ! = nullptr ) ;
NodeSpawner - > CustomizeNodeDelegate = UBlueprintNodeSpawner : : FCustomizeNodeDelegate : : CreateStatic ( CustomizeInputNodeLambda , Key ) ;
2014-09-10 17:09:26 -04:00
ActionRegistrar . AddBlueprintAction ( ActionKey , NodeSpawner ) ;
2014-07-14 13:19:37 -04:00
}
}
FText UK2Node_InputKey : : GetMenuCategory ( ) const
{
2014-09-04 13:00:27 -04:00
enum EAxisKeyCategory
{
GamepadKeyCategory ,
MouseButtonCategory ,
KeyEventCategory ,
AxisKeyCategory_MAX ,
} ;
static FNodeTextCache CachedCategories [ AxisKeyCategory_MAX ] ;
2014-07-14 13:19:37 -04:00
FText SubCategory ;
2014-09-04 13:00:27 -04:00
EAxisKeyCategory CategoryIndex = AxisKeyCategory_MAX ;
2014-07-14 13:19:37 -04:00
if ( InputKey . IsGamepadKey ( ) )
{
SubCategory = LOCTEXT ( " GamepadCategory " , " Gamepad Events " ) ;
2014-09-04 13:00:27 -04:00
CategoryIndex = GamepadKeyCategory ;
2014-07-14 13:19:37 -04:00
}
else if ( InputKey . IsMouseButton ( ) )
{
SubCategory = LOCTEXT ( " MouseCategory " , " Mouse Events " ) ;
2014-09-04 13:00:27 -04:00
CategoryIndex = MouseButtonCategory ;
2014-07-14 13:19:37 -04:00
}
else
{
SubCategory = LOCTEXT ( " KeyEventsCategory " , " Key Events " ) ;
2014-09-04 13:00:27 -04:00
CategoryIndex = KeyEventCategory ;
2014-07-14 13:19:37 -04:00
}
2015-04-02 11:16:23 -04:00
if ( CachedCategories [ CategoryIndex ] . IsOutOfDate ( this ) )
2014-09-04 13:00:27 -04:00
{
// FText::Format() is slow, so we cache this to save on performance
2015-04-02 11:16:23 -04:00
CachedCategories [ CategoryIndex ] . SetCachedText ( FEditorCategoryUtils : : BuildCategoryString ( FCommonEditorCategory : : Input , SubCategory ) , this ) ;
2014-09-04 13:00:27 -04:00
}
return CachedCategories [ CategoryIndex ] ;
2014-07-14 13:19:37 -04:00
}
2014-09-17 17:07:37 -04:00
FBlueprintNodeSignature UK2Node_InputKey : : GetSignature ( ) const
{
FBlueprintNodeSignature NodeSignature = Super : : GetSignature ( ) ;
NodeSignature . AddKeyValue ( InputKey . ToString ( ) ) ;
return NodeSignature ;
}
2014-07-14 13:19:37 -04:00
# undef LOCTEXT_NAMESPACE