mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-19 08:17:36 +00:00
Improve input box display on small screens.
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include "graphics/SharedUIDisplay.h"
|
#include "graphics/SharedUIDisplay.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace graphics
|
namespace graphics
|
||||||
{
|
{
|
||||||
@@ -70,6 +71,7 @@ void VirtualKeyboard::initializeKeyboard()
|
|||||||
|
|
||||||
void VirtualKeyboard::draw(OLEDDisplay *display, int16_t offsetX, int16_t offsetY)
|
void VirtualKeyboard::draw(OLEDDisplay *display, int16_t offsetX, int16_t offsetY)
|
||||||
{
|
{
|
||||||
|
// Repeat ticking is driven by NotificationRenderer once per frame
|
||||||
// Base styles
|
// Base styles
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
@@ -90,12 +92,6 @@ void VirtualKeyboard::draw(OLEDDisplay *display, int16_t offsetX, int16_t offset
|
|||||||
const int lastColPad = (screenW <= 128 ? 2 : 6);
|
const int lastColPad = (screenW <= 128 ? 2 : 6);
|
||||||
const int reservedLastColW = lastColLabelW + lastColPad; // reserved width for last column keys
|
const int reservedLastColW = lastColLabelW + lastColPad; // reserved width for last column keys
|
||||||
|
|
||||||
// Dynamic key geometry
|
|
||||||
int cellH = KEY_HEIGHT;
|
|
||||||
if (isWide) {
|
|
||||||
cellH = KEY_HEIGHT + 3; // slightly taller on wide screens
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always reserve width for the rightmost text column to avoid overlap on small screens
|
// Always reserve width for the rightmost text column to avoid overlap on small screens
|
||||||
int cellW = 0;
|
int cellW = 0;
|
||||||
int leftoverW = 0;
|
int leftoverW = 0;
|
||||||
@@ -110,6 +106,28 @@ void VirtualKeyboard::draw(OLEDDisplay *display, int16_t offsetX, int16_t offset
|
|||||||
leftoverW = usableW - cellW * leftCols; // distribute extra pixels over left columns (left to right)
|
leftoverW = usableW - cellW * leftCols; // distribute extra pixels over left columns (left to right)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dynamic key geometry
|
||||||
|
int cellH = KEY_HEIGHT;
|
||||||
|
if (isWide) {
|
||||||
|
// For wide screens (e.g., T114 240x135), prefer square keys: height equals left-column key width.
|
||||||
|
cellH = std::max((int)KEY_HEIGHT, cellW);
|
||||||
|
|
||||||
|
// Guarantee at least 2 lines of input are visible by reducing cell height minimally if needed.
|
||||||
|
// Replicate the spacing used in drawInputArea(): headerGap=1, box-to-header gap=1, gap above keyboard=1
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
const int headerHeight = headerText.empty() ? 0 : (FONT_HEIGHT_SMALL + 1);
|
||||||
|
const int headerToBoxGap = 1;
|
||||||
|
const int gapAboveKb = 1;
|
||||||
|
const int minBoxHeightForTwoLines = 2 * FONT_HEIGHT_SMALL + 2; // inner 1px top/bottom
|
||||||
|
int maxKeyboardHeight = screenH - (offsetY + headerHeight + headerToBoxGap + minBoxHeightForTwoLines + gapAboveKb);
|
||||||
|
int maxCellHAllowed = maxKeyboardHeight / KEYBOARD_ROWS;
|
||||||
|
if (maxCellHAllowed < (int)KEY_HEIGHT)
|
||||||
|
maxCellHAllowed = KEY_HEIGHT;
|
||||||
|
if (maxCellHAllowed > 0 && cellH > maxCellHAllowed) {
|
||||||
|
cellH = maxCellHAllowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Keyboard placement from bottom
|
// Keyboard placement from bottom
|
||||||
const int keyboardHeight = KEYBOARD_ROWS * cellH;
|
const int keyboardHeight = KEYBOARD_ROWS * cellH;
|
||||||
int keyboardStartY = screenH - keyboardHeight;
|
int keyboardStartY = screenH - keyboardHeight;
|
||||||
@@ -153,53 +171,151 @@ void VirtualKeyboard::draw(OLEDDisplay *display, int16_t offsetX, int16_t offset
|
|||||||
void VirtualKeyboard::drawInputArea(OLEDDisplay *display, int16_t offsetX, int16_t offsetY, int16_t keyboardStartY)
|
void VirtualKeyboard::drawInputArea(OLEDDisplay *display, int16_t offsetX, int16_t offsetY, int16_t keyboardStartY)
|
||||||
{
|
{
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
display->setFont(FONT_SMALL);
|
|
||||||
|
|
||||||
const int screenWidth = display->getWidth();
|
const int screenWidth = display->getWidth();
|
||||||
const int lineH = FONT_HEIGHT_SMALL;
|
const int screenHeight = display->getHeight();
|
||||||
|
// Use the standard small font metrics for input box sizing (restore original size)
|
||||||
|
const int inputLineH = FONT_HEIGHT_SMALL;
|
||||||
|
|
||||||
|
// Header uses the standard small (which may be larger on big screens)
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
int headerHeight = 0;
|
int headerHeight = 0;
|
||||||
if (!headerText.empty()) {
|
if (!headerText.empty()) {
|
||||||
|
// Draw header and reserve exact font height (plus a tighter gap) to maximize input area
|
||||||
display->drawString(offsetX + 2, offsetY, headerText.c_str());
|
display->drawString(offsetX + 2, offsetY, headerText.c_str());
|
||||||
headerHeight = 10;
|
// On very small screens (e.g., 128x64), push the input box as close as possible to the header
|
||||||
|
headerHeight = FONT_HEIGHT_SMALL; // no extra padding baked in
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input box - from below header down to just above the keyboard
|
// Input box - from below header down to just above the keyboard
|
||||||
const int boxX = offsetX + 2;
|
const int boxX = offsetX + 2;
|
||||||
const int boxY = offsetY + headerHeight + 2;
|
// Smaller gap below header on tiny screens, slightly larger otherwise
|
||||||
|
const int gapBelowHeader = (screenHeight <= 64 ? 0 : 1);
|
||||||
|
const int boxY = offsetY + headerHeight + gapBelowHeader;
|
||||||
const int boxWidth = screenWidth - 4;
|
const int boxWidth = screenWidth - 4;
|
||||||
int availableH = keyboardStartY - boxY - 2; // small gap above keyboard
|
// Ensure the box doesn't touch the keyboard: prefer a bigger guard gap on 64px screens
|
||||||
if (availableH < lineH + 2)
|
int gapAboveKeyboard = (screenHeight <= 64 ? 3 : 1);
|
||||||
availableH = lineH + 2; // ensure minimum
|
// Minimum box height to fully contain one text line with 1px padding on top and bottom
|
||||||
const int boxHeight = availableH;
|
const int minBoxHeight = inputLineH + 2;
|
||||||
|
int availableH = keyboardStartY - boxY - gapAboveKeyboard; // initial available height
|
||||||
|
if (screenHeight <= 64 && availableH < minBoxHeight) {
|
||||||
|
// Try to grow the box by reducing the gap above keyboard, but keep at least 1px separation
|
||||||
|
int need = minBoxHeight - availableH;
|
||||||
|
int canReduce = gapAboveKeyboard - 1;
|
||||||
|
int reduce = std::min(need, canReduce);
|
||||||
|
if (reduce > 0) {
|
||||||
|
gapAboveKeyboard -= reduce;
|
||||||
|
availableH = keyboardStartY - boxY - gapAboveKeyboard;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int boxHeight;
|
||||||
|
if (screenHeight <= 64) {
|
||||||
|
// On tiny screens, enforce at least one text line + 2px padding when possible
|
||||||
|
if (availableH >= minBoxHeight) {
|
||||||
|
boxHeight = availableH; // maximize
|
||||||
|
} else {
|
||||||
|
// If still not enough space, use whatever is available but keep >=1px
|
||||||
|
boxHeight = std::max(1, availableH);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (availableH < inputLineH + 2)
|
||||||
|
availableH = inputLineH + 2; // ensure minimum readability on larger screens
|
||||||
|
boxHeight = availableH;
|
||||||
|
}
|
||||||
|
|
||||||
// Draw box border
|
// Draw box border
|
||||||
display->drawRect(boxX, boxY, boxWidth, boxHeight);
|
display->drawRect(boxX, boxY, boxWidth, boxHeight);
|
||||||
|
|
||||||
|
display->setFont(FONT_SMALL);
|
||||||
|
|
||||||
// Text rendering: multi-line if space allows (>= 2 lines), else single-line with leading ellipsis
|
// Text rendering: multi-line if space allows (>= 2 lines), else single-line with leading ellipsis
|
||||||
const int textX = boxX + 2;
|
const int textX = boxX + 2;
|
||||||
const int maxTextWidth = boxWidth - 4;
|
const int maxTextWidth = boxWidth - 4;
|
||||||
const int maxLines = (boxHeight - 2) / lineH;
|
const int maxLines = (boxHeight - 2) / inputLineH;
|
||||||
if (maxLines >= 2) {
|
if (maxLines >= 2) {
|
||||||
std::string remaining = inputText;
|
// Inner bounds for caret clamping
|
||||||
int lineY = boxY + 1;
|
const int innerLeft = boxX + 1;
|
||||||
for (int line = 0; line < maxLines && !remaining.empty(); ++line) {
|
const int innerRight = boxX + boxWidth - 2;
|
||||||
int bestLen = 0;
|
const int innerTop = boxY + 1;
|
||||||
for (int len = 1; len <= (int)remaining.size(); ++len) {
|
const int innerBottom = boxY + boxHeight - 2;
|
||||||
int w = display->getStringWidth(remaining.substr(0, len).c_str());
|
|
||||||
if (w <= maxTextWidth)
|
// Wrap text greedily into lines that fit maxTextWidth
|
||||||
bestLen = len;
|
std::vector<std::string> lines;
|
||||||
else
|
{
|
||||||
break;
|
std::string remaining = inputText;
|
||||||
|
while (!remaining.empty()) {
|
||||||
|
int bestLen = 0;
|
||||||
|
for (int len = 1; len <= (int)remaining.size(); ++len) {
|
||||||
|
int w = display->getStringWidth(remaining.substr(0, len).c_str());
|
||||||
|
if (w <= maxTextWidth)
|
||||||
|
bestLen = len;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (bestLen == 0) {
|
||||||
|
// At least show one character to make progress
|
||||||
|
bestLen = 1;
|
||||||
|
}
|
||||||
|
lines.emplace_back(remaining.substr(0, bestLen));
|
||||||
|
remaining.erase(0, bestLen);
|
||||||
}
|
}
|
||||||
if (bestLen == 0)
|
|
||||||
break;
|
|
||||||
std::string chunk = remaining.substr(0, bestLen);
|
|
||||||
display->drawString(textX, lineY, chunk.c_str());
|
|
||||||
remaining.erase(0, bestLen);
|
|
||||||
lineY += lineH;
|
|
||||||
}
|
}
|
||||||
// Optional: draw cursor at end of last line could be added if needed
|
|
||||||
|
const bool scrolledUp = ((int)lines.size() > maxLines);
|
||||||
|
int caretX = textX;
|
||||||
|
int caretY = innerTop;
|
||||||
|
|
||||||
|
// Leave a small top gap to render '...' without replacing the first line
|
||||||
|
const int topInset = 2;
|
||||||
|
const int lineStep = std::max(1, inputLineH - 1); // slightly tighter than font height
|
||||||
|
int lineY = innerTop + topInset;
|
||||||
|
|
||||||
|
if (scrolledUp) {
|
||||||
|
// Draw three small dots centered horizontally, vertically at the midpoint of the gap
|
||||||
|
// between the inner top and the first line's top baseline. This avoids using a tall glyph.
|
||||||
|
const int firstLineTop = lineY; // baseline top for the first visible line
|
||||||
|
const int gapMidY = innerTop + (firstLineTop - innerTop) / 2 + 1; // shift down 1px as requested
|
||||||
|
const int centerX = boxX + boxWidth / 2;
|
||||||
|
const int dotSpacing = 3; // px between dots
|
||||||
|
const int dotSize = 1; // small square dot
|
||||||
|
display->fillRect(centerX - dotSpacing, gapMidY, dotSize, dotSize);
|
||||||
|
display->fillRect(centerX, gapMidY, dotSize, dotSize);
|
||||||
|
display->fillRect(centerX + dotSpacing, gapMidY, dotSize, dotSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// How many lines fit with our top inset and tighter step
|
||||||
|
const int linesCapacity = std::max(1, (innerBottom - lineY + 1) / lineStep);
|
||||||
|
const int linesToShow = std::min((int)lines.size(), linesCapacity);
|
||||||
|
const int startIndex = scrolledUp ? ((int)lines.size() - linesToShow) : 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < linesToShow; ++i) {
|
||||||
|
const std::string &chunk = lines[startIndex + i];
|
||||||
|
display->drawString(textX, lineY, chunk.c_str());
|
||||||
|
caretX = textX + display->getStringWidth(chunk.c_str());
|
||||||
|
caretY = lineY;
|
||||||
|
lineY += lineStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw caret at end of the last visible line
|
||||||
|
int caretPadY = 2;
|
||||||
|
if (boxHeight >= inputLineH + 4)
|
||||||
|
caretPadY = 3;
|
||||||
|
int cursorTop = caretY + caretPadY;
|
||||||
|
// Use lineStep so caret height matches the row spacing
|
||||||
|
int cursorH = lineStep - caretPadY * 2;
|
||||||
|
if (cursorH < 1)
|
||||||
|
cursorH = 1;
|
||||||
|
// Clamp vertical bounds to stay inside the inner rect
|
||||||
|
if (cursorTop < innerTop)
|
||||||
|
cursorTop = innerTop;
|
||||||
|
if (cursorTop + cursorH - 1 > innerBottom)
|
||||||
|
cursorH = innerBottom - cursorTop + 1;
|
||||||
|
if (cursorH < 1)
|
||||||
|
cursorH = 1;
|
||||||
|
// Only draw if cursor is inside inner bounds
|
||||||
|
if (caretX >= innerLeft && caretX <= innerRight) {
|
||||||
|
display->drawVerticalLine(caretX, cursorTop, cursorH);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::string displayText = inputText;
|
std::string displayText = inputText;
|
||||||
int textW = display->getStringWidth(displayText.c_str());
|
int textW = display->getStringWidth(displayText.c_str());
|
||||||
@@ -230,7 +346,12 @@ void VirtualKeyboard::drawInputArea(OLEDDisplay *display, int16_t offsetX, int16
|
|||||||
const int innerTop = boxY + 1;
|
const int innerTop = boxY + 1;
|
||||||
const int innerBottom = boxY + boxHeight - 2;
|
const int innerBottom = boxY + boxHeight - 2;
|
||||||
|
|
||||||
const int textY = boxY + 1;
|
// Position text above vertical center; total up-shift by 4px for single-line
|
||||||
|
int innerH = innerBottom - innerTop + 1;
|
||||||
|
int textY = innerTop + std::max(0, (innerH - inputLineH) / 2) - 5; // was -4, now -5
|
||||||
|
// Allow clamping to the outer border so upward shift remains visible on very small boxes
|
||||||
|
if (textY < boxY)
|
||||||
|
textY = boxY;
|
||||||
if (!scrolled.empty()) {
|
if (!scrolled.empty()) {
|
||||||
display->drawString(textX, textY, scrolled.c_str());
|
display->drawString(textX, textY, scrolled.c_str());
|
||||||
}
|
}
|
||||||
@@ -240,12 +361,9 @@ void VirtualKeyboard::drawInputArea(OLEDDisplay *display, int16_t offsetX, int16
|
|||||||
if (cursorX > innerRight)
|
if (cursorX > innerRight)
|
||||||
cursorX = innerRight;
|
cursorX = innerRight;
|
||||||
|
|
||||||
// Apply vertical padding so caret doesn't touch top/bottom
|
// Caret: height = outer box height - 4, with a 2px margin from top/bottom
|
||||||
int caretPadY = 2;
|
int cursorTop = boxY + 2;
|
||||||
if (boxHeight >= lineH + 4)
|
int cursorH = boxHeight - 4;
|
||||||
caretPadY = 3; // if box is taller than minimal, allow larger gap
|
|
||||||
int cursorTop = textY + caretPadY;
|
|
||||||
int cursorH = lineH - caretPadY * 2;
|
|
||||||
if (cursorH < 1)
|
if (cursorH < 1)
|
||||||
cursorH = 1;
|
cursorH = 1;
|
||||||
// Clamp vertical bounds to stay inside the inner rect
|
// Clamp vertical bounds to stay inside the inner rect
|
||||||
@@ -268,7 +386,7 @@ void VirtualKeyboard::drawKey(OLEDDisplay *display, const VirtualKey &key, bool
|
|||||||
{
|
{
|
||||||
// Draw key content
|
// Draw key content
|
||||||
display->setFont(FONT_SMALL);
|
display->setFont(FONT_SMALL);
|
||||||
const int fontH = FONT_HEIGHT_SMALL; // actual pixel height of current font
|
const int fontH = FONT_HEIGHT_SMALL;
|
||||||
// Build label and metrics first
|
// Build label and metrics first
|
||||||
std::string keyText;
|
std::string keyText;
|
||||||
if (key.type == VK_BACKSPACE || key.type == VK_ENTER || key.type == VK_SPACE || key.type == VK_ESC) {
|
if (key.type == VK_BACKSPACE || key.type == VK_ENTER || key.type == VK_SPACE || key.type == VK_ESC) {
|
||||||
@@ -294,32 +412,16 @@ void VirtualKeyboard::drawKey(OLEDDisplay *display, const VirtualKey &key, bool
|
|||||||
if (textX < x)
|
if (textX < x)
|
||||||
textX = x; // guard
|
textX = x; // guard
|
||||||
} else {
|
} else {
|
||||||
textX = x + ((width - textWidth) + 1) / 2; // ceil((w - tw)/2)
|
textX = x + (width - textWidth) / 2;
|
||||||
}
|
}
|
||||||
int textY = y + (height - fontH) / 2; // baseline for text
|
int contentTop = y;
|
||||||
// Per-character vertical nudge for better visual centering (only for single-character keys)
|
int contentH = height;
|
||||||
if (key.type == VK_CHAR) {
|
|
||||||
int nudge = 0;
|
|
||||||
if (keyText == "j") {
|
|
||||||
nudge = 1; // j up 1px
|
|
||||||
} else if (keyText.find_first_of("gpqy") != std::string::npos) {
|
|
||||||
nudge = 2; // g/p/q/y up 2px
|
|
||||||
} else if (keyText == ";" || keyText == "." || keyText == ",") {
|
|
||||||
nudge = 1; // ; . , up 1px to appear vertically centered
|
|
||||||
}
|
|
||||||
if (nudge) {
|
|
||||||
textY -= nudge;
|
|
||||||
if (textY < 0)
|
|
||||||
textY = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Selected: for action text buttons, highlight fits text width; for char keys, fill entire key
|
|
||||||
if (selected) {
|
if (selected) {
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
bool isAction = (key.type == VK_BACKSPACE || key.type == VK_ENTER || key.type == VK_SPACE || key.type == VK_ESC);
|
bool isAction = (key.type == VK_BACKSPACE || key.type == VK_ENTER || key.type == VK_SPACE || key.type == VK_ESC);
|
||||||
if (isAction) {
|
if (isAction) {
|
||||||
const int padX = 2; // small horizontal padding around text
|
const int padX = 2; // small horizontal padding around text
|
||||||
|
const int padY = 1; // vertical padding so highlight doesn't touch edges
|
||||||
int hlX = textX - padX;
|
int hlX = textX - padX;
|
||||||
int hlW = textWidth + padX * 2;
|
int hlW = textWidth + padX * 2;
|
||||||
// Constrain highlight within the key's horizontal span
|
// Constrain highlight within the key's horizontal span
|
||||||
@@ -333,16 +435,45 @@ void VirtualKeyboard::drawKey(OLEDDisplay *display, const VirtualKey &key, bool
|
|||||||
hlW = maxW;
|
hlW = maxW;
|
||||||
if (hlW < 1)
|
if (hlW < 1)
|
||||||
hlW = 1;
|
hlW = 1;
|
||||||
display->fillRect(hlX, y, hlW, height);
|
// Vertical: keep a small gap from top/bottom to avoid overlap with neighboring rows
|
||||||
|
int hlY = y + padY;
|
||||||
|
int hlH = height - padY * 2 + 2; // extend downward by 1px
|
||||||
|
if (hlH < 1)
|
||||||
|
hlH = 1;
|
||||||
|
display->fillRect(hlX, hlY, hlW, hlH);
|
||||||
|
// Content area (for centering text) matches highlight
|
||||||
|
contentTop = hlY;
|
||||||
|
contentH = hlH;
|
||||||
} else {
|
} else {
|
||||||
display->fillRect(x, y, width, height);
|
int hlY = y + 1;
|
||||||
|
int hlH = height + 1;
|
||||||
|
if (hlH < 1)
|
||||||
|
hlH = 1;
|
||||||
|
display->fillRect(x, hlY, width, hlH);
|
||||||
|
contentTop = hlY;
|
||||||
|
contentH = hlH;
|
||||||
}
|
}
|
||||||
display->setColor(BLACK);
|
display->setColor(BLACK);
|
||||||
} else {
|
} else {
|
||||||
display->setColor(WHITE);
|
display->setColor(WHITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
display->drawString(textX, textY, keyText.c_str());
|
int centeredTextY = contentTop + (contentH - fontH) / 2;
|
||||||
|
if (key.type == VK_CHAR) {
|
||||||
|
if (keyText.size() == 1) {
|
||||||
|
char ch = keyText[0];
|
||||||
|
bool tinyScreen = (display->getHeight() <= 64);
|
||||||
|
if (tinyScreen) {
|
||||||
|
if (ch == 'g' || ch == 'j' || ch == 'q' || ch == 'y' || ch == 'p' || ch == 'v' || ch == '.' || ch == ',' ||
|
||||||
|
ch == ';') {
|
||||||
|
centeredTextY -= 1;
|
||||||
|
if (centeredTextY < 0)
|
||||||
|
centeredTextY = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
display->drawString(textX, centeredTextY, keyText.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
char VirtualKeyboard::getCharForKey(const VirtualKey &key, bool isLongPress)
|
char VirtualKeyboard::getCharForKey(const VirtualKey &key, bool isLongPress)
|
||||||
@@ -454,10 +585,14 @@ void VirtualKeyboard::handleLongPress()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For non-character keys, long press behaves the same as regular press
|
|
||||||
switch (key.type) {
|
switch (key.type) {
|
||||||
case VK_BACKSPACE:
|
case VK_BACKSPACE:
|
||||||
deleteCharacter();
|
// One-shot: delete up to 5 characters on long press
|
||||||
|
for (int i = 0; i < 5; ++i) {
|
||||||
|
if (inputText.empty())
|
||||||
|
break;
|
||||||
|
deleteCharacter();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case VK_ENTER:
|
case VK_ENTER:
|
||||||
submitText();
|
submitText();
|
||||||
|
|||||||
Reference in New Issue
Block a user