mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-01 21:08:19 +00:00
joystick UI: proper accents, emojis stripped, new unlock mechanism
This commit is contained in:
@@ -47,19 +47,20 @@ public:
|
||||
int fontW() const { int w = mc_display_font_width(); return w ? w : 6; }
|
||||
int fontH() const { int h = mc_display_font_height(); return h ? h : 8; }
|
||||
int getTextWidth(const char *text) const {
|
||||
return text ? (int)strlen(text) * fontW() : 0;
|
||||
if (!text) return 0;
|
||||
char buf[SANITIZE_BUF];
|
||||
return (int)strlen(sanitized(buf, sizeof(buf), text)) * fontW();
|
||||
}
|
||||
|
||||
/* ===== Text drawing ===== */
|
||||
/* ===== Text drawing =====
|
||||
* All entry points transcode UTF-8 to the display charset first
|
||||
* (utf8_to_display: Latin-1/Latin-2 mapped, emoji stripped), so screens
|
||||
* can pass contact/channel names straight through. Measurement uses the
|
||||
* same transcoding, keeping widths in glyphs rather than UTF-8 bytes. */
|
||||
void drawTextLeftAlign(int x, int y, const char *text) {
|
||||
if (!text) return;
|
||||
if (_color == YELLOW) {
|
||||
int w = getTextWidth(text);
|
||||
mc_display_fill_rect(x, y, w, fontH());
|
||||
mc_display_text(x, y, text, true);
|
||||
} else {
|
||||
mc_display_text(x, y, text, _color == DARK);
|
||||
}
|
||||
char buf[SANITIZE_BUF];
|
||||
drawSanitized(x, y, sanitized(buf, sizeof(buf), text));
|
||||
}
|
||||
|
||||
void drawTextRightAlign(int right_x, int y, const char *text) {
|
||||
@@ -85,19 +86,21 @@ public:
|
||||
int avail_chars = max_w / fw;
|
||||
if (avail_chars <= 0) return;
|
||||
|
||||
int len = (int)strlen(text);
|
||||
char sbuf[SANITIZE_BUF];
|
||||
const char *s = sanitized(sbuf, sizeof(sbuf), text);
|
||||
int len = (int)strlen(s);
|
||||
if (len <= avail_chars) {
|
||||
drawTextLeftAlign(x, y, text);
|
||||
drawSanitized(x, y, s);
|
||||
} else {
|
||||
/* Truncate with "…" (3 dots, but we only have ASCII) */
|
||||
int truncate_at = avail_chars - 3;
|
||||
if (truncate_at < 0) truncate_at = 0;
|
||||
char buf[128];
|
||||
int n = truncate_at < 127 ? truncate_at : 127;
|
||||
memcpy(buf, text, n);
|
||||
memcpy(buf, s, n);
|
||||
buf[n] = '.'; buf[n+1] = '.'; buf[n+2] = '.';
|
||||
buf[n+3] = '\0';
|
||||
drawTextLeftAlign(x, y, buf);
|
||||
drawSanitized(x, y, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,12 +148,39 @@ public:
|
||||
void turnOn() { mc_display_on(); }
|
||||
void turnOff() { mc_display_off(); }
|
||||
|
||||
/* UTF8 utility */
|
||||
/* UTF8 utility — explicit pre-transcoding for screens that slice text
|
||||
* afterwards (marquee windows etc.), so byte == glyph in their math.
|
||||
* Re-sanitizing the result at draw time is a harmless pass-through. */
|
||||
void translateUTF8ToBlocks(char *dst, const char *src, int size) {
|
||||
utf8_to_latin1(dst, src, (size_t)size);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t SANITIZE_BUF = 160; /* > any display line */
|
||||
|
||||
/* Returns text itself when pure ASCII (no copy), else the transcoded
|
||||
* copy in buf. */
|
||||
static const char *sanitized(char *buf, size_t n, const char *text) {
|
||||
for (const char *p = text; *p; p++) {
|
||||
if ((uint8_t)*p >= 0x80) {
|
||||
utf8_to_display(buf, text, n);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/* Color/invert draw logic on already-transcoded text. */
|
||||
void drawSanitized(int x, int y, const char *text) {
|
||||
if (_color == YELLOW) {
|
||||
int w = (int)strlen(text) * fontW();
|
||||
mc_display_fill_rect(x, y, w, fontH());
|
||||
mc_display_text(x, y, text, true);
|
||||
} else {
|
||||
mc_display_text(x, y, text, _color == DARK);
|
||||
}
|
||||
}
|
||||
|
||||
Color _color;
|
||||
int _cx, _cy;
|
||||
};
|
||||
|
||||
@@ -657,22 +657,30 @@ void JoystickUITask::renderAlertOverlay()
|
||||
|
||||
void JoystickUITask::handleLockInput(char key, uint32_t now)
|
||||
{
|
||||
/* Unlock sequence: LEFT, OK, RIGHT — dedicated GPIO keys delivered
|
||||
* instantly. The back button is unusable here: its taps pass through
|
||||
* the longpress + multi-tap devicetree filters, so a single tap is
|
||||
* deferred 400 ms (tap-count window), a >=1 s hold becomes KEY_POWER,
|
||||
* and a quick re-tap becomes KEY_B — which made the old Back-OK-Back
|
||||
* sequence timing-sensitive. A wrong key restarts the sequence, except
|
||||
* LEFT, which always (re)arms step 1. */
|
||||
uint8_t restart = (key == KEY_LEFT) ? 1 : 0;
|
||||
|
||||
switch (_lock_step) {
|
||||
case 0:
|
||||
if (key == KEY_CANCEL) _lock_step = 1;
|
||||
else _lock_step = 0;
|
||||
_lock_step = restart;
|
||||
break;
|
||||
case 1:
|
||||
if (key == KEY_ENTER || key == KEY_ENTER_LONG) _lock_step = 2;
|
||||
else _lock_step = 0;
|
||||
else _lock_step = restart;
|
||||
break;
|
||||
case 2:
|
||||
if (key == KEY_CANCEL) {
|
||||
if (key == KEY_RIGHT) {
|
||||
_locked = false;
|
||||
_lock_step = 0;
|
||||
scheduleLockTimer();
|
||||
} else {
|
||||
_lock_step = 0;
|
||||
_lock_step = restart;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -723,7 +731,7 @@ void JoystickUITask::renderLockOverlay()
|
||||
mc_display_text((w - unread_w) / 2, 6 + fh + 6 + fh + 2, unread_buf, false);
|
||||
|
||||
/* Three step unlock sequence */
|
||||
const char *toks[3] = { "Back", "OK", "Back" };
|
||||
const char *toks[3] = { "Left", "OK", "Right" };
|
||||
const int gap = 6;
|
||||
int total_w = 0;
|
||||
for (int i = 0; i < 3; i++) total_w += (int)strlen(toks[i]) * fw;
|
||||
|
||||
@@ -203,43 +203,95 @@ static const uint8_t cfb_font_0608[224][6] = {
|
||||
/* 126 (~) */
|
||||
{ 0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00 },
|
||||
|
||||
/* === Code points 127-159 (DEL + C1 control codes) === */
|
||||
/* === Code points 127-159 (DEL + Latin-2 extras) ===
|
||||
*
|
||||
* 128-159 host the Latin Extended-A letters needed for Central European
|
||||
* names (Hungarian, Czech, Slovak, Polish, Croatian). utf8_to_display()
|
||||
* in display.c maps the Unicode code points into these slots.
|
||||
*
|
||||
* Same construction rules as the Latin-1 blocks below:
|
||||
* uppercase: base letter shifted down 1 px (<<1), accent on row 0
|
||||
* acute col3 |= 0x01
|
||||
* caron col1,col3 |= 0x01 (col2 alone is dot-above for Z;
|
||||
* side effect: E caron renders like E diaeresis)
|
||||
* double acute col2,col4 |= 0x01 (vs diaeresis col1,col3)
|
||||
* ring col1,col2,col3 |= 0x01
|
||||
* ogonek unshifted base, col4 |= 0x80 (hook on row 7)
|
||||
* lowercase: rows 0-1 free, no shift needed
|
||||
* acute col2 |= 0x01, col3 |= 0x02
|
||||
* caron col1 |= 0x01, col2 |= 0x02, col3 |= 0x01 (v shape)
|
||||
* double acute col1 |= 0x01, col2 |= 0x02, col3 |= 0x01, col4 |= 0x02
|
||||
* dot above col2 |= 0x01
|
||||
* ogonek hook below: col3/col4 |= 0x80
|
||||
*/
|
||||
|
||||
/* 127 (DEL) - blank */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
/* 128-159: C1 control codes - blank */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 128 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 129 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 130 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 131 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 132 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 133 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 134 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 135 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 136 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 137 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 138 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 139 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 140 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 141 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 142 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 143 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 144 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 145 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 146 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 147 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 148 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 149 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 150 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 151 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 152 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 153 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 154 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 155 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 156 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 157 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 158 */
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 159 */
|
||||
|
||||
/* 128 O double acute (U+0150) */
|
||||
{ 0x7C, 0x82, 0x83, 0x82, 0x7D, 0x00 },
|
||||
/* 129 o double acute (U+0151) */
|
||||
{ 0x38, 0x45, 0x46, 0x45, 0x3A, 0x00 },
|
||||
/* 130 U double acute (U+0170) */
|
||||
{ 0x7E, 0x80, 0x81, 0x80, 0x7F, 0x00 },
|
||||
/* 131 u double acute (U+0171) */
|
||||
{ 0x3C, 0x41, 0x42, 0x21, 0x7E, 0x00 },
|
||||
/* 132 A ogonek (U+0104) */
|
||||
{ 0x7E, 0x11, 0x11, 0x11, 0xFE, 0x00 },
|
||||
/* 133 a ogonek (U+0105) */
|
||||
{ 0x20, 0x54, 0x54, 0x54, 0xF8, 0x00 },
|
||||
/* 134 C acute (U+0106) */
|
||||
{ 0x7C, 0x82, 0x82, 0x83, 0x44, 0x00 },
|
||||
/* 135 c acute (U+0107) */
|
||||
{ 0x38, 0x44, 0x45, 0x46, 0x20, 0x00 },
|
||||
/* 136 C caron (U+010C) */
|
||||
{ 0x7C, 0x83, 0x82, 0x83, 0x44, 0x00 },
|
||||
/* 137 c caron (U+010D) */
|
||||
{ 0x38, 0x45, 0x46, 0x45, 0x20, 0x00 },
|
||||
/* 138 E caron (U+011A) */
|
||||
{ 0xFE, 0x93, 0x92, 0x93, 0x82, 0x00 },
|
||||
/* 139 e caron (U+011B) */
|
||||
{ 0x38, 0x55, 0x56, 0x55, 0x18, 0x00 },
|
||||
/* 140 E ogonek (U+0118) */
|
||||
{ 0x7F, 0x49, 0x49, 0x49, 0xC1, 0x00 },
|
||||
/* 141 e ogonek (U+0119) */
|
||||
{ 0x38, 0x54, 0x54, 0xD4, 0x18, 0x00 },
|
||||
/* 142 L stroke (U+0141) */
|
||||
{ 0x7F, 0x48, 0x44, 0x40, 0x40, 0x00 },
|
||||
/* 143 l stroke (U+0142) */
|
||||
{ 0x00, 0x51, 0x7F, 0x44, 0x00, 0x00 },
|
||||
/* 144 N acute (U+0143) */
|
||||
{ 0xFE, 0x08, 0x10, 0x21, 0xFE, 0x00 },
|
||||
/* 145 n acute (U+0144) */
|
||||
{ 0x7C, 0x08, 0x05, 0x06, 0x78, 0x00 },
|
||||
/* 146 R caron (U+0158) */
|
||||
{ 0xFE, 0x13, 0x32, 0x53, 0x8C, 0x00 },
|
||||
/* 147 r caron (U+0159) */
|
||||
{ 0x7C, 0x09, 0x06, 0x05, 0x08, 0x00 },
|
||||
/* 148 S acute (U+015A) */
|
||||
{ 0x8C, 0x92, 0x92, 0x93, 0x62, 0x00 },
|
||||
/* 149 s acute (U+015B) */
|
||||
{ 0x48, 0x54, 0x55, 0x56, 0x20, 0x00 },
|
||||
/* 150 S caron (U+0160) */
|
||||
{ 0x8C, 0x93, 0x92, 0x93, 0x62, 0x00 },
|
||||
/* 151 s caron (U+0161) */
|
||||
{ 0x48, 0x55, 0x56, 0x55, 0x20, 0x00 },
|
||||
/* 152 U ring (U+016E) */
|
||||
{ 0x7E, 0x81, 0x81, 0x81, 0x7E, 0x00 },
|
||||
/* 153 u ring (U+016F) */
|
||||
{ 0x3C, 0x42, 0x41, 0x22, 0x7C, 0x00 },
|
||||
/* 154 Z acute (U+0179) */
|
||||
{ 0xC2, 0xA2, 0x92, 0x8B, 0x86, 0x00 },
|
||||
/* 155 z acute (U+017A) */
|
||||
{ 0x44, 0x64, 0x55, 0x4E, 0x44, 0x00 },
|
||||
/* 156 Z dot above (U+017B) */
|
||||
{ 0xC2, 0xA2, 0x93, 0x8A, 0x86, 0x00 },
|
||||
/* 157 z dot above (U+017C) */
|
||||
{ 0x44, 0x64, 0x55, 0x4C, 0x44, 0x00 },
|
||||
/* 158 Z caron (U+017D) */
|
||||
{ 0xC2, 0xA3, 0x92, 0x8B, 0x86, 0x00 },
|
||||
/* 159 z caron (U+017E) */
|
||||
{ 0x44, 0x65, 0x56, 0x4D, 0x44, 0x00 },
|
||||
|
||||
/* === Latin-1 Supplement 160-255 === */
|
||||
|
||||
|
||||
+105
-16
@@ -565,45 +565,134 @@ const struct device *mc_display_get_device(void)
|
||||
return disp_initialized ? disp_dev : NULL;
|
||||
}
|
||||
|
||||
/* ========== UTF-8 to Latin-1 Sanitizer ========== */
|
||||
void utf8_to_latin1(char *dst, const char *src, size_t dst_size)
|
||||
/* ========== UTF-8 to display-charset sanitizer ==========
|
||||
*
|
||||
* The 6x8 font covers Latin-1 at its native code points (0xA0-0xFF) and
|
||||
* hosts 32 Latin Extended-A letters (Hungarian, Czech, Slovak, Polish, ...)
|
||||
* in the otherwise-unused C1 range 128-159 (see cfb_font_0608.c). */
|
||||
|
||||
/* Latin Extended-A code points with a real glyph -> font slot 128-159 */
|
||||
static const struct {
|
||||
uint16_t cp;
|
||||
uint8_t slot;
|
||||
} latin2_slots[] = {
|
||||
{ 0x0104, 132 }, { 0x0105, 133 }, /* A/a ogonek */
|
||||
{ 0x0106, 134 }, { 0x0107, 135 }, /* C/c acute */
|
||||
{ 0x010C, 136 }, { 0x010D, 137 }, /* C/c caron */
|
||||
{ 0x0118, 140 }, { 0x0119, 141 }, /* E/e ogonek */
|
||||
{ 0x011A, 138 }, { 0x011B, 139 }, /* E/e caron */
|
||||
{ 0x0141, 142 }, { 0x0142, 143 }, /* L/l stroke */
|
||||
{ 0x0143, 144 }, { 0x0144, 145 }, /* N/n acute */
|
||||
{ 0x0150, 128 }, { 0x0151, 129 }, /* O/o double acute */
|
||||
{ 0x0158, 146 }, { 0x0159, 147 }, /* R/r caron */
|
||||
{ 0x015A, 148 }, { 0x015B, 149 }, /* S/s acute */
|
||||
{ 0x0160, 150 }, { 0x0161, 151 }, /* S/s caron */
|
||||
{ 0x016E, 152 }, { 0x016F, 153 }, /* U/u ring */
|
||||
{ 0x0170, 130 }, { 0x0171, 131 }, /* U/u double acute */
|
||||
{ 0x0179, 154 }, { 0x017A, 155 }, /* Z/z acute */
|
||||
{ 0x017B, 156 }, { 0x017C, 157 }, /* Z/z dot above */
|
||||
{ 0x017D, 158 }, { 0x017E, 159 }, /* Z/z caron */
|
||||
};
|
||||
|
||||
/* Base-letter fold for all of Latin Extended-A (U+0100..U+017F), indexed by
|
||||
* cp - 0x100. Used for code points without a glyph slot above. */
|
||||
static const char latin_ext_a_fold[] =
|
||||
"AaAaAa" "CcCcCcCc" "DdDd" "EeEeEeEeEe" "GgGgGgGg" "HhHh"
|
||||
"IiIiIiIiIi" "Ii" "Jj" "Kkk" "LlLlLlLlLl" "NnNnNnnNn"
|
||||
"OoOoOoOo" "RrRrRr" "SsSsSsSs" "TtTtTt" "UuUuUuUuUuUu"
|
||||
"Ww" "YyY" "ZzZzZz" "s";
|
||||
|
||||
static uint8_t display_charset_map(uint32_t cp)
|
||||
{
|
||||
if (cp >= 0xA0 && cp <= 0xFF) {
|
||||
return (uint8_t)cp; /* native Latin-1 glyph */
|
||||
}
|
||||
if (cp >= 0x100 && cp <= 0x17F) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(latin2_slots); i++) {
|
||||
if (latin2_slots[i].cp == cp) {
|
||||
return latin2_slots[i].slot;
|
||||
}
|
||||
}
|
||||
return (uint8_t)latin_ext_a_fold[cp - 0x100];
|
||||
}
|
||||
switch (cp) { /* Romanian uses comma-below variants */
|
||||
case 0x218: return 'S';
|
||||
case 0x219: return 's';
|
||||
case 0x21A: return 'T';
|
||||
case 0x21B: return 't';
|
||||
default: return 0; /* drop: emoji, other scripts, ... */
|
||||
}
|
||||
}
|
||||
|
||||
void utf8_to_display(char *dst, const char *src, size_t dst_size)
|
||||
{
|
||||
size_t di = 0;
|
||||
size_t si = 0;
|
||||
|
||||
if (dst_size == 0) {
|
||||
return;
|
||||
}
|
||||
while (src[si] && di < dst_size - 1) {
|
||||
uint8_t c = (uint8_t)src[si];
|
||||
uint32_t cp;
|
||||
int len;
|
||||
|
||||
if (c < 0x80) {
|
||||
dst[di++] = (char)c;
|
||||
si++;
|
||||
continue;
|
||||
} else if ((c & 0xE0) == 0xC0) {
|
||||
uint8_t c2 = (uint8_t)src[si + 1];
|
||||
|
||||
if ((c2 & 0xC0) != 0x80) {
|
||||
si++;
|
||||
continue;
|
||||
}
|
||||
uint16_t cp = ((c & 0x1F) << 6) | (c2 & 0x3F);
|
||||
if (cp >= 0xA0 && cp <= 0xFF) {
|
||||
dst[di++] = (char)(uint8_t)cp;
|
||||
}
|
||||
si += 2;
|
||||
cp = c & 0x1F;
|
||||
len = 2;
|
||||
} else if ((c & 0xF0) == 0xE0) {
|
||||
si += 3;
|
||||
cp = c & 0x0F;
|
||||
len = 3;
|
||||
} else if ((c & 0xF8) == 0xF0) {
|
||||
si += 4;
|
||||
cp = c & 0x07;
|
||||
len = 4;
|
||||
} else {
|
||||
/* Not a UTF-8 lead byte: already display-encoded text
|
||||
* (or junk) — pass through so a second sanitizing pass
|
||||
* is harmless. */
|
||||
dst[di++] = (char)c;
|
||||
si++;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool valid = true;
|
||||
for (int k = 1; k < len; k++) {
|
||||
if (((uint8_t)src[si + k] & 0xC0) != 0x80) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
cp = (cp << 6) | ((uint8_t)src[si + k] & 0x3F);
|
||||
}
|
||||
if (!valid) {
|
||||
dst[di++] = (char)c; /* lone lead byte: pass through */
|
||||
si++;
|
||||
continue;
|
||||
}
|
||||
si += len;
|
||||
|
||||
uint8_t out = display_charset_map(cp);
|
||||
if (out) {
|
||||
dst[di++] = (char)out;
|
||||
}
|
||||
}
|
||||
dst[di] = '\0';
|
||||
}
|
||||
|
||||
/* Legacy entry point: transcode + trim leading spaces (names are sometimes
|
||||
* space-padded to game sort order). */
|
||||
void utf8_to_latin1(char *dst, const char *src, size_t dst_size)
|
||||
{
|
||||
utf8_to_display(dst, src, dst_size);
|
||||
|
||||
size_t start = 0;
|
||||
while (dst[start] == ' ') {
|
||||
start++;
|
||||
}
|
||||
if (start > 0) {
|
||||
memmove(dst, dst + start, di - start + 1);
|
||||
memmove(dst, dst + start, strlen(dst + start) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,9 +174,19 @@ void mc_display_epd_full_reset(void);
|
||||
const struct device *mc_display_get_device(void);
|
||||
|
||||
/**
|
||||
* Convert UTF-8 text to Latin-1 for display rendering.
|
||||
* Passes ASCII unchanged, converts 2-byte Latin-1 (U+00A0-U+00FF),
|
||||
* strips everything else (emojis, CJK). Trims leading spaces left by stripped chars.
|
||||
* Convert UTF-8 text to the display charset for rendering.
|
||||
* Passes ASCII unchanged, converts Latin-1 (U+00A0-U+00FF) to its native
|
||||
* code points, maps 32 Latin-2 letters (Hungarian/Czech/Slovak/Polish/...)
|
||||
* into font slots 128-159, folds the rest of Latin Extended-A to base ASCII
|
||||
* letters, and strips everything else (emojis, CJK). Bytes that are not
|
||||
* valid UTF-8 pass through unchanged, so already-converted text survives a
|
||||
* second pass.
|
||||
*/
|
||||
void utf8_to_display(char *dst, const char *src, size_t dst_size);
|
||||
|
||||
/**
|
||||
* utf8_to_display() + leading-space trim (names are sometimes space-padded
|
||||
* to game sort order).
|
||||
*/
|
||||
void utf8_to_latin1(char *dst, const char *src, size_t dst_size);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user