2021-08-15 11:09 PM
I know TouchGFX provide a template for keyboard, but the layout is far from what I need. What I need is something like our typical numeric keypad in our standard PC keyboard ( the one on right hand side).
When I take a look the sample code, it seems not trivial, there are 3 cpp/hpp files that I can see. Can someone give me pointer how to proceed?
If there is a ready sample would be great, if not please advice me which files need to be modified. Or maybe I can break down my questions:
I recommend ST make a sample demo for this as this is very typical usage and there would be many developers looking for it
2021-08-17 11:18 PM
2021-08-17 11:40 PM
I have difficulty to modify existing keyboard sample in TouchGFX, it seems I have to change also class Keyboard which seems not possible for user as the code is in platform level and I dont think meant for user to change
2021-08-18 10:12 PM
Hi @Martin KJELDSEN , I wonder if you could help me please, I have been stucked for days.
I tried to change what I can from the original TouchGFX keyboard template, but still cant achieve the layout that I want as posted above. I have modified these files but seem would allow me to achieve the layout I want:
Could you give me some pointers to achieve that layout please.
2021-08-19 3:13 AM
I made a custom container "CustomContainerInputFloatValue" which has similar layout but additional keys for decimal seperator, +/- and backspace and clear.
For each key, in interactions I defined a virtual function, e.g. goKey1.
This function checks, if it is allowed to add the new key and appends the key to a string.
The screen which uses the custom container retrieves the value with getValue().
I can also set the required range of value and the decimal point (point or comma).
Maybe you can use this as a base.
Here is the header file:
#ifndef CUSTOMCONTAINERINPUTFLOATVALUE_HPP
#define CUSTOMCONTAINERINPUTFLOATVALUE_HPP
#include <gui_generated/containers/CustomContainerInputFloatValueBase.hpp>
const int strFloatValueBufferSize = 20;
class CustomContainerInputFloatValue : public CustomContainerInputFloatValueBase
{
public:
CustomContainerInputFloatValue();
virtual ~CustomContainerInputFloatValue() {}
virtual void initialize();
// functions called is a key is pressed:
virtual void goKey0();
virtual void goKey1();
virtual void goKey2();
virtual void goKey3();
virtual void goKey4();
virtual void goKey5();
virtual void goKey6();
virtual void goKey7();
virtual void goKey8();
virtual void goKey9();
virtual void goKeyDecimalPoint();
virtual void goKeyPlusMinus();
virtual void goKeyBackspace();
virtual void goKeyBackword();
virtual void setDefaultValue(float value);
virtual void setDecimalPoint(char decimalPt);
virtual void setMinValueAllowed(float f);
virtual void setMaxValueAllowed(float f);
// update text field
virtual void update();
// true, if new value is within allowed range
virtual bool isAddCharPossible(char ch);
virtual void addChar(char ch);
virtual bool isEqual(const char * string);
virtual void clear();
virtual float getValue();
char m_str[strFloatValueBufferSize];
char decimalPoint;
float minValueAllowed;
float maxValueAllowed;
protected:
};
#endif // CUSTOMCONTAINERINPUTFLOATVALUE_HPP
2021-08-19 3:16 AM
And here is the cpp file:
#include <gui/containers/CustomContainerInputFloatValue.hpp>
#include <cstring>
CustomContainerInputFloatValue::CustomContainerInputFloatValue()
{
decimalPoint = '.';
minValueAllowed = 0;
maxValueAllowed = 100;
}
void CustomContainerInputFloatValue::initialize()
{
CustomContainerInputFloatValueBase::initialize();
}
void CustomContainerInputFloatValue::goKey0()
{
if (! isEqual("0"))
{
if (isAddCharPossible('0'))
{
addChar('0');
}
update();
}
}
void CustomContainerInputFloatValue::goKey1()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('1'))
{
addChar('1');
}
update();
}
void CustomContainerInputFloatValue::goKey2()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('2'))
{
addChar('2');
}
update();
}
void CustomContainerInputFloatValue::goKey3()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('3'))
{
addChar('3');
}
update();
}
void CustomContainerInputFloatValue::goKey4()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('4'))
{
addChar('4');
}
update();
}
void CustomContainerInputFloatValue::goKey5()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('5'))
{
addChar('5');
}
update();
}
void CustomContainerInputFloatValue::goKey6()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('6'))
{
addChar('6');
}
update();
}
void CustomContainerInputFloatValue::goKey7()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('7'))
{
addChar('7');
}
update();
}
void CustomContainerInputFloatValue::goKey8()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('8'))
{
addChar('8');
}
update();
}
void CustomContainerInputFloatValue::goKey9()
{
if (isEqual("0"))
{
clear();
}
if (isAddCharPossible('9'))
{
addChar('9');
}
update();
}
void CustomContainerInputFloatValue::goKeyDecimalPoint()
{
if (strlen(m_str) == 0)
{
addChar('0');
}
if (strchr(m_str, decimalPoint) == 0)
{
addChar(decimalPoint);
}
update();
}
void CustomContainerInputFloatValue::goKeyBackspace()
{
size_t l = strlen(m_str);
if (l > 0 && l <= strFloatValueBufferSize)
{
m_str [l-1] = 0;
update();
}
}
void CustomContainerInputFloatValue::goKeyBackword()
{
clear();
update();
}
void CustomContainerInputFloatValue::goKeyPlusMinus()
{
size_t l = strlen(m_str);
if (isEqual("0"))
{
clear();
addChar('-');
}
else if ((l > 1) && (m_str[0] == '-'))
{
if (l < strFloatValueBufferSize)
{
// remove first character
for (size_t n = 1; n < strFloatValueBufferSize; n++)
{
m_str[n-1] = m_str[n];
}
m_str[l-1] = 0;
}
}
else if (l >= 1)
{
// insert -
if (l < strFloatValueBufferSize)
{
for (size_t n = l; n; n--)
{
m_str[n] = m_str[n-1];
}
m_str[0] = '-';
m_str[strFloatValueBufferSize - 1] = 0;
}
}
update();
}
void CustomContainerInputFloatValue::update()
{
(void) Unicode::snprintf(textArea1Buffer, TEXTAREA1_SIZE, m_str);
textArea1.invalidate();
if (minValueAllowed < 0)
{
buttonKeyPlusMinus.setVisible(true);
}
else
{
buttonKeyPlusMinus.setVisible(false);
}
buttonKeyPlusMinus.invalidate();
}
void CustomContainerInputFloatValue::addChar(char ch)
{
size_t l = strlen(m_str);
if (l < (strFloatValueBufferSize-1))
{
m_str[l] = ch;
m_str[l+1] = 0;
}
}
bool CustomContainerInputFloatValue::isAddCharPossible(char ch)
{
bool b = false;
char str[strFloatValueBufferSize];
(void) strncpy(str, m_str, strFloatValueBufferSize);
size_t l = strlen(str);
if (l < (strFloatValueBufferSize-1))
{
str[l] = ch;
str[l+1] = 0;
float f = awiStrUtil::getFloat(str, strFloatValueBufferSize, decimalPoint);
if (f <= maxValueAllowed)
{
b = true;
}
}
return b;
}
void CustomContainerInputFloatValue::clear()
{
m_str[0] = 0;
}
bool CustomContainerInputFloatValue::isEqual(const char * string)
{
bool b = false;
if (string)
{
if (strcmp(string, m_str) == 0)
{
b = true;
}
}
return b;
}
void CustomContainerInputFloatValue::setDefaultValue(float value)
{
awiStrUtil::printFloat(value, -1, m_str, strFloatValueBufferSize, decimalPoint);
update();
}
void CustomContainerInputFloatValue::setDecimalPoint(char decimalPt)
{
decimalPoint = decimalPt;
}
float CustomContainerInputFloatValue::getValue()
{
return awiStrUtil::getFloat(m_str, strFloatValueBufferSize, decimalPoint);
}
void CustomContainerInputFloatValue::setMaxValueAllowed(float f)
{
maxValueAllowed = f;
}
void CustomContainerInputFloatValue::setMinValueAllowed(float f)
{
minValueAllowed = f;
}
2021-08-19 4:12 AM
to be complete, if float is needed and the decimal point could also be a comma:
namespace awiStrUtil {
float getFloat(char * valbuf, size_t valbufSize, char decimalPoint)
{
const int bufSize = 20;
char buf[bufSize];
for (size_t i = 0; (i < valbufSize) && (i < bufSize); i++)
{
buf[i] = valbuf[i];
if (buf[i] == decimalPoint && decimalPoint != '.')
{
buf[i] = '.';
}
}
buf[valbufSize - 1] = 0;
return atof(buf);
}
void printFloat(float value, int precision, char * valbuf, size_t valbufSize, char decimalPoint)
{
// would give an error with simulator: "-Werror=format-nonliteral"
// snprintf(valbuf, valbufSize, getFloatFormatString(precision), value);
switch (precision)
{
case -1:
{
(void) snprintf(valbuf, valbufSize, "%f", value);
// remove trailing 0 (after decimal point)
int l = strlen(valbuf);
bool decimalFound = false;
for (int i = 0; i < l; i++)
{
if (valbuf[i] == '.')
{
decimalFound = true;
break;
}
}
if (decimalFound)
{
for (int i = l; i; i--)
{
if (valbuf[i-1] == '0')
{
valbuf[i-1] = 0;
}
else
{
if (valbuf[i-1] == '.')
{
valbuf[i-1] = 0;
}
break;
}
}
}
}
break;
case 0: (void) snprintf(valbuf, valbufSize, "%.0f", value); break;
case 1: (void) snprintf(valbuf, valbufSize, "%.1f", value); break;
case 2: (void) snprintf(valbuf, valbufSize, "%.2f", value); break;
case 3: (void) snprintf(valbuf, valbufSize, "%.3f", value); break;
case 4: (void) snprintf(valbuf, valbufSize, "%.4f", value); break;
case 5: (void) snprintf(valbuf, valbufSize, "%.5f", value); break;
case 6: (void) snprintf(valbuf, valbufSize, "%.6f", value); break;
case 7: (void) snprintf(valbuf, valbufSize, "%.7f", value); break;
default:
(void) snprintf(valbuf, valbufSize, "***"); break;
break;
}
//#pragma GCC diagnostic pop
// replace . by ,
if (decimalPoint != '.')
{
for (size_t i = 0; i < valbufSize; i++)
{
if (valbuf[i] == 0)
{
break;
}
else if (valbuf[i] == '.')
{
valbuf[i] = decimalPoint;
}
}
}
}
}
2021-08-23 5:14 AM
thank you @awiernie , I can leverage some of ideas, but for my usage, I decide to code keyboard behavior by myself instead of using TouchGFX sample as base.
2021-08-23 5:17 AM
> but for my usage, I decide to code keyboard behavior by myself instead of using TouchGFX sample as base
My solution does not use TouchGFX sample as base.
2021-08-23 6:09 AM
From my opinion, it is easy to modify CustomKeyboard demo to meet your challenge, you need to modify KeyboardKeyMapping.hpp and KeyboardLayout.hpp, and modify CustomKeyboard.cpp accordingly(delete unused callbacks).
We’re moving the ST Community to a new platform to give you a better and more reliable community experience.