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 03: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 03: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 04: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 05: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 05: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 06: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).