Input
This is the native Engine.Input class, which holds the aliases and keybinds configured in the User.ini file.
Structure - as defined in C++
enum {ALIAS_MAX=40}; struct FAlias { FName Alias; FString Command; FAlias() : Alias(), Command(E_NoInit) {} }; class ENGINE_API UInput : public USubsystem { static const TCHAR* StaticConfigName() { return TEXT("User"); } DECLARE_CLASS(UInput,USubsystem,CLASS_Transient|CLASS_Config,Engine) // Variables. FAlias Aliases[ALIAS_MAX]; FStringNoInit Bindings[IK_MAX]; UViewport* Viewport; // Constructors. UInput(); void StaticConstructor(); // UObject interface. void Serialize( FArchive& Ar ); // UInput interface. static void StaticInitInput(); virtual void Init (UViewport* Viewport); virtual UBOOL Exec (const TCHAR* Cmd, FOutputDevice& Ar); virtual UBOOL PreProcess (EInputKey iKey, EInputAction State, FLOAT Delta = 0.f); virtual UBOOL Process (FOutputDevice& Ar, EInputKey iKey, EInputAction State, FLOAT Delta = 0.f); virtual void DirectAxis (EInputKey Key, FLOAT Length, FLOAT Delta); virtual void ReadInput (FLOAT DeltaSeconds, FOutputDevice& Ar); virtual void ResetInput (); virtual const TCHAR* GetKeyName (EInputKey Key) const; virtual int FindKeyName (const TCHAR* KeyName, EInputKey& iKey) const; // Accessors. void SetInputAction (EInputAction NewAction, FLOAT NewDelta = 0.f) { Action = NewAction; Delta = NewDelta; } EInputAction GetInputAction () { return Action; } FLOAT GetInputDelta () { return Delta; } BYTE KeyDown (int i) { return KeyDownTable[Clamp(i,0,IK_MAX-1)]; } protected: UEnum* InputKeys; EInputAction Action; FLOAT Delta; BYTE KeyDownTable[IK_MAX]; virtual BYTE* FindButtonName (AActor* Actor, const TCHAR* ButtonName) const; virtual FLOAT* FindAxisName (AActor* Actor, const TCHAR* ButtonName) const; virtual void ExecInputCommands (const TCHAR* Cmd, FOutputDevice& Ar); };
Hypothetical Code
void UInput :: Init (UViewport* InViewport) { guard(UInput::Init); Viewport = InViewport; debugf(NAME_Init, TEXT("Input system initialized for %s"),Viewport->GetName()); unguard; } const TCHAR* UInput :: GetKeyName (EInputKey Key) const { guard(UInput::GetKeyName); FString KeyName; if ((Key >= 0) && (Key < IK_MAX)) { KeyName = *(FString*)EInputKey->Names(Key); return KeyName.Mid(3); } return TEXT(""); unguard; } UBOOL UInput :: FindKeyName (const TCHAR* KeyName, EInputKey& iKey) const { guard(UInput::FindKeyName); INT i, j; FString Key; for (i = 0; i < IK_MAX; ++ i) { Key = *(FString*)EInputKey->Names(i); Key = Key.Mid(3); if (KeyName.Caps() == Key.Caps()) { j = i; break; } } return j; unguard; }
Variable Interpretation
- UEnum* InputKeys;
enum EInputKey { IK_None, IK_LeftMouse, // This is IK_Mouse on Mac IK_RightMouse, // This is IK_AltMouse on Mac IK_Cancel, IK_MiddleMouse, // This is IK_Unknown04 on Mac IK_Unknown05, IK_Unknown06, IK_Unknown07, IK_Backspace, IK_Tab, IK_Unknown0A, IK_Unknown0B, IK_Unknown0C, IK_Enter, IK_Unknown0E, IK_Unknown0F, IK_Shift, IK_Ctrl, IK_Alt, // This is IK_Option on Mac IK_Pause, IK_CapsLock, IK_Unknown15, IK_Unknown16, IK_Unknown17, IK_Unknown18, IK_Unknown19, IK_Unknown1A, IK_Escape, IK_Unknown1C, IK_Unknown1D, IK_Unknown1E, IK_Unknown1F, IK_Space, IK_PageUp, IK_PageDown, IK_End, IK_Home, IK_Left, IK_Up, IK_Right, IK_Down, IK_Select, IK_Print, IK_Execute, IK_PrintScrn, IK_Insert, IK_Delete, IK_Help, IK_0, IK_1, IK_2, IK_3, IK_4, IK_5, IK_6, IK_7, IK_8, IK_9, IK_Unknown3A, IK_Unknown3B, IK_Unknown3C, IK_Unknown3D, IK_Unknown3E, IK_Unknown3F, IK_Unknown40, IK_A, IK_B, IK_C, IK_D, IK_E, IK_F, IK_G, IK_H, IK_I, IK_J, IK_K, IK_L, IK_M, IK_N, IK_O, IK_P, IK_Q, IK_R, IK_S, IK_T, IK_U, IK_V, IK_W, IK_X, IK_Y, IK_Z, IK_Unknown5B, // This is the start menu key in every OS IK_Unknown5C, // This is the start menu key in every OS (the one on the right) IK_Unknown5D, // This is the MouseMenu in Windows (the one next to the right start menu key) IK_Unknown5E, IK_Unknown5F, IK_NumPad0, IK_NumPad1, IK_NumPad2, IK_NumPad3, IK_NumPad4, IK_NumPad5, IK_NumPad6, IK_NumPad7, IK_NumPad8, IK_NumPad9, IK_GreyStar, // This is IK_NumPadStar on Mac IK_GreyPlus, // This is IK_NumPadPlus on Mac IK_Separator, IK_GreyMinus, // This is IK_NumPadMinus on Mac IK_NumPadPeriod, IK_GreySlash, // This is IK_NumPadSlash on Mac IK_F1, IK_F2, IK_F3, IK_F4, IK_F5, IK_F6, IK_F7, IK_F8, IK_F9, IK_F10, IK_F11, IK_F12, IK_F13, IK_F14, IK_F15, IK_F16, IK_F17, IK_F18, IK_F19, IK_F20, IK_F21, IK_F22, IK_F23, IK_F24, IK_Unknown88, // This is IK_NumPadEquals on Mac IK_Unknown89, // This is IK_Command on Mac IK_Unknown8A, IK_Unknown8B, IK_Unknown8C, IK_Unknown8D, IK_Unknown8E, IK_Unknown8F, IK_NumLock, IK_ScrollLock, IK_Unknown92, IK_Unknown93, IK_Unknown94, IK_Unknown95, IK_Unknown96, IK_Unknown97, IK_Unknown98, IK_Unknown99, IK_Unknown9A, IK_Unknown9B, IK_Unknown9C, IK_Unknown9D, IK_Unknown9E, IK_Unknown9F, IK_LShift, IK_RShift, IK_LControl, IK_RControl, IK_UnknownA4, IK_UnknownA5, IK_UnknownA6, IK_UnknownA7, IK_UnknownA8, IK_UnknownA9, IK_UnknownAA, IK_UnknownAB, IK_UnknownAC, IK_UnknownAD, IK_UnknownAE, IK_UnknownAF, IK_UnknownB0, IK_UnknownB1, IK_UnknownB2, IK_UnknownB3, IK_UnknownB4, IK_UnknownB5, IK_UnknownB6, IK_UnknownB7, IK_UnknownB8, IK_UnknownB9, IK_Semicolon, IK_Equals, IK_Comma, IK_Minus, IK_Period, IK_Slash, IK_Tilde, IK_UnknownC1, IK_UnknownC2, IK_UnknownC3, IK_UnknownC4, IK_UnknownC5, IK_UnknownC6, IK_UnknownC7, IK_Joy1, IK_Joy2, IK_Joy3, IK_Joy4, IK_Joy5, IK_Joy6, IK_Joy7, IK_Joy8, IK_Joy9, IK_Joy10, IK_Joy11, IK_Joy12, IK_Joy13, IK_Joy14, IK_Joy15, IK_Joy16, IK_UnknownD8, IK_UnknownD9, IK_UnknownDA, IK_LeftBracket, IK_Backslash, IK_RightBracket, IK_SingleQuote, IK_UnknownDF, IK_JoyX, IK_JoyY, IK_JoyZ, IK_JoyR, IK_MouseX, IK_MouseY, IK_MouseZ, IK_MouseW, IK_JoyU, IK_JoyV, IK_UnknownEA, IK_UnknownEB, IK_MouseWheelUp, IK_MouseWheelDown, IK_UnknownEE, // Typo: IK_Unknown10E IK_UnknownEF, // Typo: UK_Unknown10F IK_JoyPovUp, IK_JoyPovDown, IK_JoyPovLeft, IK_JoyPovRight, IK_UnknownF4, IK_UnknownF5, IK_Attn, IK_CrSel, IK_ExSel, IK_ErEof, IK_Play, IK_Zoom, IK_NoName, IK_PA1, IK_OEMClear };
Note: There is a typo IK_Unknown10E and another of UK_Unknown10F in the UScript and C++ versions of the EInput enum; The correct ones are IK_UnknownEE and IK_UnknownEF.
- EInputAction Action
enum EInputAction { IST_None, // Not performing special input processing. IST_Press, // Handling a keypress or button press. IST_Hold, // Handling holding a key or button. IST_Release, // Handling a key or button release. IST_Axis, // Handling analog axis movement. };
- FLOAT Delta
- possibly used for the Axis movement (?)
- BYTE KeyDownTable[IK_MAX]
- monitors which keys are pressed
Code Interpretation
- StaticInitInput()
- This most likely assembles the InputKeys, that is, convert the 255-arrayed string Bindings to the normal EInput version of itself we see in the INI.
- Init()
- basic initialization function; assigns the viewport and writes the debug output... might call StaticInitInput()
- Exec()
- handles native console commands; in this case, it might handle the INI commands such as Button, Toggle, keyname etc.
- DirectAxis()
- controls the axis movement of "special" keys, such as the Mouse or Joystick axis
- ResetInput()
- can be called from PlayerPawn.ResetKeyboard() (UT) or PlayerController.ResetKeyboard() (UT2k3 and UT2k4)
Assuming the KeyDownTable[] is constantly monitored, the order might be this:
- PreProcess()
- checks whether a key is pressed or not, similar to the Console handling of keys using IST_Press and IST_Release
- ReadInput()
- hypothesized to be the Tick() equivalent of the Input which might constantly check which key is currently used, possibly even call PlayerPawn.PlayerInput() (UT); in UT2k3 and UT2k4 PlayerInput() is handled by PlayerTick() and is in a separate class
- Process()
- possibly controls the exec-ing of console commands from each key in the INI if active in the KeyDownTable[] array
Accessing The Input Configuration
While it is possible to compile code that references class'Input' or Input objects, it's not possible to access properties of purely native classes directly in UnrealScript. (compiles fine, but crashes the game)
To work around this problem you first need a reference to an Input object. Under UT200x you can easily get such a reference with the following code:
local Input MyInput; foreach AllObjects(class'Input', MyInput) break;
The variable MyInput will then contain the currently used Input object.
In UT there is no AllObjects iterator, so you have to resort to a little trick with the SetPropertyText() function:
var Input MyInput; function GetInput() { SetPropertyText("MyInput", "Input'Input0'"); }
The Input object should always have this name, so SetPropertyText() assigns it to the MyInput class variable. You could use this unter UT200x as well, but depending on whether the game was started with the -makenames parameter you have to use either "Input'Input'" (without) or "Input'Input0'" (with) to get the desired effect.
Either way you can now access the Input object with the GetPropertyText function:
// log the command bound to the left mouse button log(MyInput.GetPropertyText("LeftMouse"));
Under UT2004 you can also access the Aliases array this way, but you will probably have to parse the array string first.
Beginning with UT2004 v3270 there's also an easier method of accessing aliases and keybinds using the Security class LocalPerform() function with a SecType of 100 and 101 respectively. See the UnrealScript Source of the XGame.XPlayer class for an implementation example. It's a good idea to spawn a new Security actor there, because the custom Security actors of Anti TCC and probably also SafeGame won't allow others to access their LocalPerform() function.
Category Class (UT)
Category Class (UT2003)
Category Class (UT2004)