Coded keypad
January 2024
You can help by adding links to this article from other relevant articles.
January 2024
A functional keypad for the Source engine. Inspirated on SysOp's keypad code for GoldSrc, I made my own for the Source engine.
Features:
- Close and clear buttons.
- Hover and click effects on the buttons.
- Customizable keypad text.
- Typed code can be set to be hidden.
- Has outputs for correct and incorrect codes.
Coded on Source SDK 2013 SinglePlayer Episodic, but it should be compatible for NonEpisodic and Multiplayer codes. Credit me (Maestro Fénix) and SysOp if you are going to use it on your mod. This is for everyone.
You can see a video demostration of it here.
Contents
Client
vgui_keypad.h
//==========================================================================//
//
// Purpose: VGUI Keypad made by Maestro Fénix 2015
//
// $NoKeywords: $
//===========================================================================//
using namespace vgui;
#include <vgui/IVGui.h>
#include <vgui_controls/Frame.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/ImagePanel.h>
#include <vgui_controls/Label.h>
#include <vgui_controls\Panel.h>
#include <vgui\ISurface.h>
#include "usermessages.h" //For user messages at keypad
#include "hud_macros.h" //Needed for networking messages
#include "hudelement.h" //Needed for networking messages
#include "iclientmode.h" //Needed for getting the viewport of the player
#include "engine/IEngineSound.h" //For sounds
class CVgui_keypad : public vgui::Frame, public CHudElement
{
DECLARE_CLASS(CVgui_keypad, vgui::Frame);
public:
CVgui_keypad(const char *pElementName); // Constructor vgui::VPANEL parent
~CVgui_keypad(){}; // Destructor
void CheckPass(int number);
void OnTick();
void Init();
void MsgFunc_KeypadHandler(bf_read &msg);
protected:
//VGUI overrides:
void PaintBackground();
void Paint();
virtual void OnCommand(const char* pcCommand);
virtual void OnThink(void);
private:
//Other used VGUI control Elements:
ImagePanel *m_pBackgroundPanel;
Button *m_pCloseButton;
Button *m_pClearButton;
Button *m_pMenuButtons[100];
Label *m_pScreenTitle;
Label *m_pLabel;
ImagePanel *m_imgMenuButtons[100];
ImagePanel *m_imgClearButton;
ImagePanel *m_imgCloseButton;
char szCode[32];
int m_pPressedNumbers;
char szEnteredNumbers[32];
bool m_pHidePass;
char szFrameLabel[32];
bool m_showKeypad;
};
vgui_keypad.cpp
//==========================================================================//
//
// Purpose: VGUI Keypad made by Maestro Fénix 2015
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "vgui_keypad.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//Disable this and all the related for debug purposes
//ConVar cl_showkeypad("cl_showkeypad", "0", FCVAR_HIDDEN, "Toggles keypad panel <state>");
DECLARE_HUDELEMENT(CVgui_keypad);
DECLARE_HUD_MESSAGE(CVgui_keypad, KeypadHandler)
CVgui_keypad::CVgui_keypad(const char *pElementName) : CHudElement(pElementName), BaseClass(NULL, "Vgui_keypad") //vgui::VPANEL parent
{
m_showKeypad = false;
vgui::Panel *parent = g_pClientMode->GetViewport();
SetParent(parent);
SetTitleBarVisible(false);
SetMinimizeButtonVisible(false);
SetMaximizeButtonVisible(false);
SetCloseButtonVisible(false);
SetSizeable(false);
SetMoveable(false);
SetSize(300, 600);
vgui::ivgui()->AddTickSignal(GetVPanel(), 100);
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
LoadControlSettings("resource/ui/keypad.res");
//Keypad background
m_pBackgroundPanel = FindControl<ImagePanel>("KeypadBackground", true); //Searches at the RES file the button, so we can modify it here
m_pBackgroundPanel->SetImage(scheme()->GetImage("keypad/keypad_base", false));
m_pBackgroundPanel->SetSize(512, 1024);
//Close Button
m_pCloseButton = FindControl<Button>("ButtonCls", true);
m_pCloseButton->SetDepressedSound("buttons/blip1.wav");
m_pCloseButton->SetAlpha(0);
m_pCloseButton->SetSize(64, 64);
m_imgCloseButton = FindControl<ImagePanel>("ButtonClsImg", true);
m_imgCloseButton->SetImage("keypad/keypad_close");
m_imgCloseButton->SetSize(64, 64);
//Clear Button
m_pClearButton = FindControl<Button>("ButtonClr", true);
m_pClearButton->SetAlpha(0);
m_pClearButton->SetDepressedSound("buttons/blip1.wav");
m_pClearButton->SetSize(64, 64);
m_imgClearButton = FindControl<ImagePanel>("ButtonClrImg", true);
m_imgClearButton->SetImage("keypad/keypad_clear");
m_imgClearButton->SetSize(64, 64);
//Code viewport
m_pLabel = FindControl<Label>("KeypadLabel", true);
m_pLabel->SetVisible(true);
m_pLabel->SetText("");
IScheme *pScheme = scheme()->GetIScheme(GetScheme());
HFont font = pScheme->GetFont("CreditsText");
m_pLabel->SetFont(font);
m_pLabel->SetWide(512);
//Keypad screen text
m_pScreenTitle = FindControl<Label>("KeypadLabelTitle", true);
m_pScreenTitle->SetVisible(true);
font = pScheme->GetFont("CreditsText");
m_pScreenTitle->SetFont(font);
m_pScreenTitle->SetWide(512);
//NumPad Buttons
//FUgly, find a way to do it on a loop
m_pMenuButtons[0] = FindControl<Button>("KeypadButton0", true);
m_pMenuButtons[1] = FindControl<Button>("KeypadButton1", true);
m_pMenuButtons[2] = FindControl<Button>("KeypadButton2", true);
m_pMenuButtons[3] = FindControl<Button>("KeypadButton3", true);
m_pMenuButtons[4] = FindControl<Button>("KeypadButton4", true);
m_pMenuButtons[5] = FindControl<Button>("KeypadButton5", true);
m_pMenuButtons[6] = FindControl<Button>("KeypadButton6", true);
m_pMenuButtons[7] = FindControl<Button>("KeypadButton7", true);
m_pMenuButtons[8] = FindControl<Button>("KeypadButton8", true);
m_pMenuButtons[9] = FindControl<Button>("KeypadButton9", true);
m_imgMenuButtons[0] = FindControl<ImagePanel>("KeypadButton0img", true);
m_imgMenuButtons[0]->SetImage("keypad/keypad_0");
m_imgMenuButtons[1] = FindControl<ImagePanel>("KeypadButton1img", true);
m_imgMenuButtons[1]->SetImage("keypad/keypad_1");
m_imgMenuButtons[2] = FindControl<ImagePanel>("KeypadButton2img", true);
m_imgMenuButtons[2]->SetImage("keypad/keypad_2");
m_imgMenuButtons[3] = FindControl<ImagePanel>("KeypadButton3img", true);
m_imgMenuButtons[3]->SetImage("keypad/keypad_3");
m_imgMenuButtons[4] = FindControl<ImagePanel>("KeypadButton4img", true);
m_imgMenuButtons[4]->SetImage("keypad/keypad_4");
m_imgMenuButtons[5] = FindControl<ImagePanel>("KeypadButton5img", true);
m_imgMenuButtons[5]->SetImage("keypad/keypad_5");
m_imgMenuButtons[6] = FindControl<ImagePanel>("KeypadButton6img", true);
m_imgMenuButtons[6]->SetImage("keypad/keypad_6");
m_imgMenuButtons[7] = FindControl<ImagePanel>("KeypadButton7img", true);
m_imgMenuButtons[7]->SetImage("keypad/keypad_7");
m_imgMenuButtons[8] = FindControl<ImagePanel>("KeypadButton8img", true);
m_imgMenuButtons[8]->SetImage("keypad/keypad_8");
m_imgMenuButtons[9] = FindControl<ImagePanel>("KeypadButton9img", true);
m_imgMenuButtons[9]->SetImage("keypad/keypad_9");
for (int i = 0; i < 10; i++)
{
m_pMenuButtons[i]->SetDepressedSound("buttons/blip1.wav");
m_pMenuButtons[i]->SetAlpha(0);
m_pMenuButtons[i]->SetSize(32, 32);
m_imgMenuButtons[i]->SetSize(32, 32);
}
}
void CVgui_keypad::Init()
{
//Gets the message sent from from func_keypad: code, keypad title and if code must be hidden
HOOK_HUD_MESSAGE(CVgui_keypad, KeypadHandler);
}
void CVgui_keypad::PaintBackground()
{
//vgui::surface()->DrawSetColor(255, 0, 0, 255);
}
void CVgui_keypad::Paint()
{
//Change this value if you want a longer pass
if (m_pPressedNumbers == 4)
{
//Disable to check into DEV mode if the codes are correct
//Transforms the char into a int so we really get the number itself
/*char * numberC;
int numberN = strtol(szEnteredNumbers, &numberC, 10);
DevMsg("Code entered is: %i \n", numberN);
numberN = strtol(szCode, &numberC, 10);
DevMsg("Correct code is: %i \n", numberN);*/
//Checks if the code is the good one
if (strcmp(szEnteredNumbers, szCode))
{
engine->ClientCmd("keypad_codematch");
/*Mysteriously enough, as soon as keypad_codematch is fired,
it runs the stuff at the other side. That's why stuff
is mixed on both places*/
//Wrong code is set
surface()->PlaySound("buttons/button2.wav");
m_pPressedNumbers = 0;
}
else
{
engine->ClientCmd("keypad_codedismatch");
/*Mysteriously enough, as soon as keypad_codedismatch is fired,
it runs the stuff at the other side. That's why stuff
is mixed on both places*/
//Correct code is set
surface()->PlaySound("buttons/button5.wav");
SetVisible(false);
m_showKeypad = false;
//cl_showkeypad.SetValue(0);
m_pPressedNumbers = 0;
}
}
//Makes buttons go grey if they are pushed
for (int i = 0; i < 10; i++)
{
if (m_pMenuButtons[i]->IsArmed())
{
m_imgMenuButtons[i]->SetAlpha(255);
}
else
{
m_imgMenuButtons[i]->SetAlpha(150);
}
}
if (m_pClearButton->IsArmed())
{
m_imgClearButton->SetAlpha(255);
}
else
{
m_imgClearButton->SetAlpha(150);
}
if (m_pCloseButton->IsArmed())
{
m_imgCloseButton->SetAlpha(255);
}
else
{
m_imgCloseButton->SetAlpha(150);
}
}
void CVgui_keypad::OnTick()
{
BaseClass::OnTick();
}
void CVgui_keypad::OnCommand(const char* pcCommand)
{
BaseClass::OnCommand(pcCommand);
if (!Q_stricmp(pcCommand, "clear"))
{
m_pPressedNumbers = 0;
m_pLabel->SetText("");
}
if (!Q_stricmp(pcCommand, "turnoff"))
{
//cl_showkeypad.SetValue(0);
m_showKeypad = false;
}
//ToDo: Search a better way to do this
if (!Q_stricmp(pcCommand, "0"))
{
CheckPass(0);
}
if (!Q_stricmp(pcCommand, "1"))
{
CheckPass(1);
}
if (!Q_stricmp(pcCommand, "2"))
{
CheckPass(2);
}
if (!Q_stricmp(pcCommand, "3"))
{
CheckPass(3);
}
if (!Q_stricmp(pcCommand, "4"))
{
CheckPass(4);
}
if (!Q_stricmp(pcCommand, "5"))
{
CheckPass(5);
}
if (!Q_stricmp(pcCommand, "6"))
{
CheckPass(6);
}
if (!Q_stricmp(pcCommand, "7"))
{
CheckPass(7);
}
if (!Q_stricmp(pcCommand, "8"))
{
CheckPass(8);
}
if (!Q_stricmp(pcCommand, "9"))
{
CheckPass(9);
}
}
void CVgui_keypad::CheckPass(int number)
{
//Disable if you wanna check on DEV mode if the number pressed is correct
//DevMsg("Number entered is: %i \n", number);
//We need the number as a string
char numberN[8];
sprintf(numberN, "%i", number);
//Used to check how many numbers we are adding
m_pPressedNumbers++;
//Add the new number, otherwise, display the first one
if (m_pPressedNumbers >1)
strcat(szEnteredNumbers, numberN);
else
strcpy(szEnteredNumbers, numberN);
//Disable if you wanna check on DEV mode if the code is correct
//DevMsg("Code entered is: %i \n", szEnteredNumbers);
m_pLabel->SetVisible(true);
//If is enabled to hide numbers, do so
if (m_pHidePass)
{
//SysOp: so fucking lazy, blame me
if (m_pPressedNumbers == 1)
m_pLabel->SetText("*");
if (m_pPressedNumbers == 2)
m_pLabel->SetText("**");
if (m_pPressedNumbers == 3)
m_pLabel->SetText("***");
if (m_pPressedNumbers == 4)
m_pLabel->SetText("****");
}
else
{
//Show the number itself then
m_pLabel->SetText(szEnteredNumbers);
}
}
// declare the user message handler
void CVgui_keypad::MsgFunc_KeypadHandler(bf_read &msg)
{
msg.ReadString(szCode, sizeof(szCode));
msg.ReadString(szFrameLabel, sizeof(szFrameLabel));
m_pScreenTitle->SetText(szFrameLabel);
m_pHidePass = msg.ReadByte();
//cl_showkeypad.SetValue(1);
m_showKeypad = true;
}
void CVgui_keypad::OnThink(void)
{
if (m_showKeypad) //cl_showkeypad.GetBool()
{
SetVisible(true);
SetMouseInputEnabled(true);
//Fix for known VGUI bug with SetMouseInputEnabled making the keyboard not accepting two or more pressed buttons
SetKeyBoardInputEnabled(true);
}
else
{
SetVisible(false);
SetMouseInputEnabled(false);
//Fix for known VGUI bug with SetMouseInputEnabled making the keyboard not accepting two or more pressed buttons
SetKeyBoardInputEnabled(false);
}
BaseClass::OnThink();
}
Server
point_keypad.h
//==========================================================================//
//
// Purpose: VGUI Keypad made by Maestro Fénix 2015
//
// $NoKeywords: $
//===========================================================================//
class CPointKeypad : public CPointEntity
{
public:
DECLARE_CLASS(CPointKeypad, CPointEntity);
void Spawn(void);
void Precache(void);
bool KeyValue(const char *szKeyName, const char *szValue);
//BOOL m_bNeedsUpdate;
string_t s_code;
string_t s_frame_label;
bool b_hide_pass;
void FireTarget(void);
void WrongCode(void);
private:
void Enable(inputdata_t &inputdata);
COutputEvent OnCorrectCode;
COutputEvent OnIncorrectCode;
DECLARE_DATADESC();
};
point_keypad.cpp
//==========================================================================//
//
// Purpose: VGUI Keypad made by Maestro Fénix 2015
//
// $NoKeywords: $
//===========================================================================//
#include "cbase.h"
#include "point_keypad.h"
#include "baseentity.h"
#include "entityinput.h"
#include "entityoutput.h"
#include "recipientfilter.h"
#include "usermessages.h" //For user messages at keypad
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS(point_keypad, CPointKeypad);
BEGIN_DATADESC(CPointKeypad)
DEFINE_FIELD(s_code, FIELD_STRING),
DEFINE_FIELD(s_frame_label, FIELD_STRING),
DEFINE_FIELD(b_hide_pass, FIELD_BOOLEAN),
//Inputs
DEFINE_INPUTFUNC(FIELD_VOID, "Enable", Enable),
//Outputs
DEFINE_OUTPUT(OnCorrectCode, "OnCorrectCode"),
DEFINE_OUTPUT(OnIncorrectCode, "OnIncorrectCode")
END_DATADESC()
void CPointKeypad::Spawn(void)
{
Precache();
SetSolid(SOLID_NONE);
SetMoveType(MOVETYPE_NONE);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPointKeypad::Precache(void)
{
}
//-----------------------------------------------------------------------------
// Purpose: Cache user-entity-field values until spawn is called.
// Input : szKeyName -
// szValue -
// Output : Returns true if handled, false if not.
//-----------------------------------------------------------------------------
bool CPointKeypad::KeyValue(const char *szKeyName, const char *szValue)
{
if (FStrEq(szKeyName, "code"))
{
s_code = AllocPooledString(szValue);
}
else if (FStrEq(szKeyName, "label"))
{
s_frame_label = AllocPooledString(szValue);
}
else if (FStrEq(szKeyName, "hide_pass"))
{
b_hide_pass = (atoi(szValue) !=0 );
}
else
{
return CPointEntity::KeyValue(szKeyName, szValue);
}
return true;
}
void CPointKeypad::Enable(inputdata_t &inputdata)
{
CBasePlayer *pPlayer = NULL;
if (inputdata.pActivator && inputdata.pActivator->IsPlayer())
{
pPlayer = ToBasePlayer(inputdata.pActivator);
}
else
{
pPlayer = UTIL_GetLocalPlayer();
}
CSingleUserRecipientFilter user(pPlayer);
//user.MakeReliable(); Needed?
UserMessageBegin(user, "KeypadHandler");
WRITE_STRING(STRING(s_code));//password
WRITE_STRING(STRING(s_frame_label));//what's displayed on LCD screen
WRITE_BOOL(b_hide_pass);//hide password option
MessageEnd();
}
//-----------------------------------------------------------------------------
// Purpose: this function is callled when the user introduced the correct code and vgui sent a command(keypad_codematch) and
// the command(keypad_codematch) checks if there is a keypad that needs that code(see player.cpp)
//-----------------------------------------------------------------------------
void CPointKeypad::FireTarget(void)
{
OnCorrectCode.FireOutput(this, this);
}
//-----------------------------------------------------------------------------
// Purpose: this function is callled when the user introduced the incorrect code and vgui sent a command(keypad_codedismatch) and
// the command(keypad_codedismatch) checks if there is a keypad that needs that code(see player.cpp)
//-----------------------------------------------------------------------------
void CPointKeypad::WrongCode(void)
{
OnIncorrectCode.FireOutput(this, this);
}
player.cpp
Go to player.cpp and at the top add an include for point_keypad.h
#include "point_keypad.h"
Now search for this function:
else if ( stricmp( cmd, "playerperf" ) == 0 )
Paste the following code after it (in the case you can't find it, just place it inside the bool CBasePlayer::ClientCommand( const CCommand &args ) function ):
//Keypad
else if (stricmp(cmd, "keypad_codematch"))
{
CBaseEntity *pEntity = NULL;
//while ((pEntity = gEntList.FindEntityByClassnameWithin(pEntity, "player", GetLocalOrigin(), 512)) != NULL)
// CBasePlayer *pPlayer = ToBasePlayer(pEntity);
while ((pEntity = gEntList.FindEntityInSphere(pEntity, GetLocalOrigin(), 512)) != NULL)//512
{
if (FClassnameIs(pEntity, "point_keypad"))
{
edict_t *pFind;
pFind = pEntity->edict();
CBaseEntity *pEnt = CBaseEntity::Instance(pFind);
CPointKeypad *pKeypadSettings = (CPointKeypad *)pEnt;
//DevMsg("code_match - firing FireTarget\n");
pKeypadSettings->FireTarget();
return true;
}
}
}
else if (stricmp(cmd, "keypad_codedismatch"))
{
CBaseEntity *pEntity = NULL;
// while ((pEntity = gEntList.FindEntityByClassnameWithin(pEntity, "player", GetLocalOrigin(), 512)) != NULL)
// CBasePlayer *pPlayer = ToBasePlayer(pEntity);
//same as above, but calls a different function
while ((pEntity = gEntList.FindEntityInSphere(pEntity, GetLocalOrigin(), 512)) != NULL)//512
{
if (FClassnameIs(pEntity, "point_keypad"))
{
edict_t *pFind;
pFind = pEntity->edict();
CBaseEntity *pEnt = CBaseEntity::Instance(pFind);
CPointKeypad *pKeypadSettings = (CPointKeypad *)pEnt;
//DevMsg("code_dismatch - firing WrongCode\n");
pKeypadSettings->WrongCode();
return true;
}
}
}
hl2_usermessages.cpp
Go to shared/hl2/hl2_usermessages.cpp, and add the following inside the "void RegisterUserMessages( void )" function:
usermessages->Register("KeypadHandler", -1); //Keypad
FGD
Add this to your mod.fgd:
@PointClass base(Targetname) size(-8 -8 -8, 8 8 8) = point_keypad : "An interactive keypad that fires outputs depending if is correct " +
"or not the introduced code."
[
//my_target(string) : "Target" : ""
code(string) : "Code (MAX 4!)" : "1234"
label(string) : "Label" : "Mah keypad"
hide_pass(choices) : "Hide password?" : "1" =
[
"0" : "No"
"1": "Yes"
]
// Inputs
input Enable(void) : "Enables the keypad."
// Outputs
output OnCorrectCode(void) : "Fired when the code is correct."
output OnIncorrectCode(void) : "Fired when the code is incorrect."
]
keypad.res
Place the following RES file in resource/ui/:
"resource/ui/keypad.res"
{
"Vgui_keypad"
{
"ControlName" "Frame"
"fieldName" "Vgui_keypad"
"xpos" "c-150"
"ypos" "c-200"
"visible" "0"
"enabled" "0"
}
"frame_topGrip"
{
"ControlName" "Panel"
"fieldName" "frame_topGrip"
"visible" "0"
"enabled" "0"
}
"frame_bottomGrip"
{
"ControlName" "Panel"
"fieldName" "frame_bottomGrip"
"visible" "0"
"enabled" "0"
"tabPosition" "0"
}
"frame_leftGrip"
{
"ControlName" "Panel"
"fieldName" "frame_leftGrip"
"visible" "0"
"enabled" "0"
}
"frame_rightGrip"
{
"ControlName" "Panel"
"fieldName" "frame_rightGrip"
"visible" "0"
"enabled" "0"
}
"frame_tlGrip"
{
"ControlName" "Panel"
"fieldName" "frame_tlGrip"
"visible" "0"
"enabled" "0"
}
"frame_trGrip"
{
"ControlName" "Panel"
"fieldName" "frame_trGrip"
"visible" "0"
"enabled" "0"
}
"frame_blGrip"
{
"ControlName" "Panel"
"fieldName" "frame_blGrip"
"visible" "0"
"enabled" "0"
}
"frame_brGrip"
{
"ControlName" "Panel"
"fieldName" "frame_brGrip"
"visible" "0"
"enabled" "0"
}
"frame_caption"
{
"ControlName" "Panel"
"fieldName" "frame_caption"
"visible" "0"
"enabled" "0"
}
"frame_minimize"
{
"ControlName" "Button"
"fieldName" "frame_minimize"
"visible" "0"
"enabled" "0"
}
"frame_maximize"
{
"ControlName" "Button"
"fieldName" "frame_maximize"
"visible" "0"
"enabled" "0"
}
"frame_mintosystray"
{
"ControlName" "Button"
"fieldName" "frame_mintosystray"
"visible" "0"
"enabled" "0"
}
"frame_close"
{
"ControlName" "Button"
"fieldName" "frame_close"
"visible" "0"
"enabled" "0"
}
"frame_menu"
{
"ControlName" "FrameSystemButton"
"fieldName" "frame_menu"
"visible" "0"
"enabled" "0"
}
"KeypadBackground"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadBackground"
"xpos" "-4"
"ypos" "34"
"zpos" "1"
"wide" "227"
"tall" "455"
}
"KeypadLabelTitle"
{
"ControlName" "Label"
"fieldName" "KeypadLabelTitle"
"xpos" "43"
"ypos" "100"
"zpos" "2"
"wide" "227"
"tall" "13"
}
"KeypadLabel"
{
"ControlName" "Label"
"fieldName" "KeypadLabel"
"xpos" "43"
"ypos" "130"
"zpos" "2"
"wide" "227"
"tall" "13"
}
"KeypadButton0"
{
"ControlName" "Button"
"fieldName" "KeypadButton0"
"xpos" "105"
"ypos" "320"
"zpos" "3"
"command" "0"
}
"KeypadButton0img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton0img"
"xpos" "105"
"ypos" "320"
"zpos" "2"
}
"KeypadButton1"
{
"ControlName" "Button"
"fieldName" "KeypadButton1"
"xpos" "65"
"ypos" "170"
"zpos" "3"
"command" "1"
}
"KeypadButton1img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton1img"
"xpos" "65"
"ypos" "170"
"zpos" "2"
}
"KeypadButton2"
{
"ControlName" "Button"
"fieldName" "KeypadButton2"
"xpos" "105"
"ypos" "170"
"zpos" "3"
"command" "2"
}
"KeypadButton2img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton2img"
"xpos" "105"
"ypos" "170"
"zpos" "2"
}
"KeypadButton3"
{
"ControlName" "Button"
"fieldName" "KeypadButton3"
"xpos" "145"
"ypos" "170"
"zpos" "3"
"command" "3"
}
"KeypadButton3img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton3img"
"xpos" "145"
"ypos" "170"
"zpos" "2"
}
"KeypadButton4"
{
"ControlName" "Button"
"fieldName" "KeypadButton4"
"xpos" "65"
"ypos" "220"
"zpos" "3"
"command" "4"
}
"KeypadButton4img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton4img"
"xpos" "65"
"ypos" "220"
"zpos" "2"
}
"KeypadButton5"
{
"ControlName" "Button"
"fieldName" "KeypadButton5"
"xpos" "105"
"ypos" "220"
"zpos" "3"
"command" "5"
}
"KeypadButton5img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton5img"
"xpos" "105"
"ypos" "220"
"zpos" "2"
}
"KeypadButton6"
{
"ControlName" "Button"
"fieldName" "KeypadButton6"
"xpos" "145"
"ypos" "220"
"zpos" "3"
"command" "6"
}
"KeypadButton6img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton6img"
"xpos" "145"
"ypos" "220"
"zpos" "2"
}
"KeypadButton7"
{
"ControlName" "Button"
"fieldName" "KeypadButton7"
"xpos" "65"
"ypos" "270"
"zpos" "3"
"command" "7"
}
"KeypadButton7img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton7img"
"xpos" "65"
"ypos" "270"
"zpos" "2"
}
"KeypadButton8"
{
"ControlName" "Button"
"fieldName" "KeypadButton8"
"xpos" "105"
"ypos" "270"
"zpos" "3"
"command" "8"
}
"KeypadButton8img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton8img"
"xpos" "105"
"ypos" "270"
"zpos" "2"
}
"KeypadButton9"
{
"ControlName" "Button"
"fieldName" "KeypadButton9"
"xpos" "145"
"ypos" "270"
"zpos" "3"
"command" "9"
}
"KeypadButton9img"
{
"ControlName" "ImagePanel"
"fieldName" "KeypadButton9img"
"xpos" "145"
"ypos" "270"
"zpos" "2"
}
"ButtonCls"
{
"ControlName" "Button"
"fieldName" "ButtonCls"
"xpos" "140"
"ypos" "400"
"zpos" "3"
"command" "turnoff"
}
"ButtonClsImg"
{
"ControlName" "ImagePanel"
"fieldName" "ButtonClsImg"
"xpos" "140"
"ypos" "400"
"zpos" "2"
}
"ButtonClr"
{
"ControlName" "Button"
"fieldName" "ButtonClr"
"xpos" "40"
"ypos" "400"
"zpos" "3"
"command" "clear"
}
"ButtonClrImg"
{
"ControlName" "ImagePanel"
"fieldName" "ButtonClrImg"
"xpos" "40"
"ypos" "400"
"zpos" "2"
}
}
GitHub link
In case you prefer to download the files, as well as the test map and the textures for it: https://github.com/MaestroFenix/Keypad