Fix multibyte letters in keyboard and input prompt

This commit is contained in:
Pk11 2021-08-19 22:26:57 -05:00 committed by d0k3
parent 0275a85121
commit 830479f50c
3 changed files with 139 additions and 47 deletions

View File

@ -119,34 +119,50 @@ static void DrawKeyBoard(TouchBox* swkbd, const u32 uppercase) {
} }
static void DrawTextBox(const TouchBox* txtbox, const char* inputstr, const u32 cursor, u32* scroll) { static void DrawTextBox(const TouchBox* txtbox, const char* inputstr, const u32 cursor, u32* scroll) {
const u32 input_shown = (txtbox->w / FONT_WIDTH_EXT) - 2; const u32 input_shown_length = (txtbox->w / FONT_WIDTH_EXT) - 2;
const u32 inputstr_size = strlen(inputstr); // we rely on a zero terminated string const u32 inputstr_size = strlen(inputstr); // we rely on a zero terminated string
const u16 x = txtbox->x; const u16 x = txtbox->x;
const u16 y = txtbox->y; const u16 y = txtbox->y;
// fix scroll // fix scroll
if (cursor < *scroll) *scroll = cursor; if (cursor < *scroll) {
else if (cursor - *scroll > input_shown) *scroll = cursor - input_shown; *scroll = cursor;
} else {
int scroll_adjust = -input_shown_length;
for (u32 i = *scroll; i < cursor; i++) {
if (i >= inputstr_size || (inputstr[i] & 0xC0) != 0x80) scroll_adjust++;
}
for (int i = 0; i < scroll_adjust; i++)
*scroll += *scroll >= inputstr_size ? 1 : GetCharSize(inputstr + *scroll);
}
u32 input_shown_size = 0;
for (u32 i = 0; i < input_shown_length || (*scroll + input_shown_size < inputstr_size && (inputstr[*scroll + input_shown_size] & 0xC0) == 0x80); input_shown_size++) {
if (*scroll + input_shown_size >= inputstr_size || (inputstr[*scroll + input_shown_size] & 0xC0) != 0x80) i++;
}
// draw input string // draw input string
DrawStringF(BOT_SCREEN, x, y, COLOR_STD_FONT, COLOR_STD_BG, "%c%-*.*s%-*.*s%c", DrawStringF(BOT_SCREEN, x, y, COLOR_STD_FONT, COLOR_STD_BG, "%c%-*.*s%c",
(*scroll) ? '<' : '|', (*scroll) ? '<' : '|',
(inputstr_size > input_shown) ? input_shown : inputstr_size, input_shown_size,
(inputstr_size > input_shown) ? input_shown : inputstr_size, input_shown_size,
(*scroll > inputstr_size) ? "" : inputstr + *scroll, (*scroll > inputstr_size) ? "" : inputstr + *scroll,
(inputstr_size > input_shown) ? 0 : input_shown - inputstr_size, (inputstr_size - (s32) *scroll > input_shown_size) ? '>' : '|'
(inputstr_size > input_shown) ? 0 : input_shown - inputstr_size,
"",
(inputstr_size - (s32) *scroll > input_shown) ? '>' : '|'
); );
// draw cursor // draw cursor
u16 cpos = 0;
for (u16 i = *scroll; i < cursor; i++) {
if (i >= inputstr_size || (inputstr[i] & 0xC0) != 0x80) cpos++;
}
DrawStringF(BOT_SCREEN, x-(FONT_WIDTH_EXT/2), y+10, COLOR_STD_FONT, COLOR_STD_BG, "%-*.*s^%-*.*s", DrawStringF(BOT_SCREEN, x-(FONT_WIDTH_EXT/2), y+10, COLOR_STD_FONT, COLOR_STD_BG, "%-*.*s^%-*.*s",
1 + cursor - *scroll, 1 + cpos,
1 + cursor - *scroll, 1 + cpos,
"", "",
input_shown - (cursor - *scroll), input_shown_length - cpos,
input_shown - (cursor - *scroll), input_shown_length - cpos,
"" ""
); );
} }
@ -163,8 +179,17 @@ static void MoveTextBoxCursor(const TouchBox* txtbox, const char* inputstr, cons
const TouchBox* tb = TouchBoxGet(&id, x, y, txtbox, 0); const TouchBox* tb = TouchBoxGet(&id, x, y, txtbox, 0);
if (id == KEY_TXTBOX) { if (id == KEY_TXTBOX) {
u16 x_tb = x - tb->x; u16 x_tb = x - tb->x;
u16 cpos = (x_tb < (FONT_WIDTH_EXT/2)) ? 0 : (x_tb - (FONT_WIDTH_EXT/2)) / FONT_WIDTH_EXT;
u32 cursor_next = *scroll + ((cpos <= input_shown) ? cpos : input_shown); const u32 inputstr_size = strlen(inputstr);
const u16 cpos_x = (x_tb < (FONT_WIDTH_EXT/2)) ? 0 : (x_tb - (FONT_WIDTH_EXT/2)) / FONT_WIDTH_EXT;
u16 cpos_length = 0;
u16 cpos_size = 0;
while ((cpos_length < cpos_x && cpos_length < input_shown) || (*scroll + cpos_size < inputstr_size && (inputstr[*scroll + cpos_size] & 0xC0) == 0x80)) {
if (*scroll + cpos_size >= inputstr_size || (inputstr[*scroll + cpos_size] & 0xC0) != 0x80) cpos_length++;
cpos_size++;
}
u32 cursor_next = *scroll + cpos_size;
// move cursor to position pointed to // move cursor to position pointed to
if (*cursor != cursor_next) { if (*cursor != cursor_next) {
if (cursor_next < max_size) *cursor = cursor_next; if (cursor_next < max_size) *cursor = cursor_next;
@ -173,10 +198,10 @@ static void MoveTextBoxCursor(const TouchBox* txtbox, const char* inputstr, cons
} }
// move beyound visible field // move beyound visible field
if (timer_msec(timer) >= scroll_cooldown) { if (timer_msec(timer) >= scroll_cooldown) {
if ((cpos == 0) && (*scroll > 0)) if ((cpos_length == 0) && (*scroll > 0))
(*scroll)--; *scroll -= GetPrevCharSize(inputstr + *scroll);
else if ((cpos >= input_shown) && (*cursor < (max_size-1))) else if ((cpos_length >= input_shown) && (*cursor < (max_size-1)))
(*scroll)++; *scroll += GetCharSize(inputstr + *scroll);
} }
} }
} }
@ -286,16 +311,18 @@ bool ShowKeyboard(char* inputstr, const u32 max_size, const char *format, ...) {
break; break;
} else if (key == KEY_BKSPC) { } else if (key == KEY_BKSPC) {
if (cursor) { if (cursor) {
int size = GetPrevCharSize(inputstr + cursor);
if (cursor <= inputstr_size) { if (cursor <= inputstr_size) {
memmove(inputstr + cursor - 1, inputstr + cursor, inputstr_size - cursor + 1); memmove(inputstr + cursor - size, inputstr + cursor, inputstr_size - cursor + size);
inputstr_size--; inputstr_size -= size;
} }
cursor--; cursor -= size;
} }
} else if (key == KEY_LEFT) { } else if (key == KEY_LEFT) {
if (cursor) cursor--; if (cursor) cursor -= GetPrevCharSize(inputstr + cursor);
} else if (key == KEY_RIGHT) { } else if (key == KEY_RIGHT) {
if (cursor < (max_size-1)) cursor++; int size = cursor > inputstr_size ? 1 : GetCharSize(inputstr + cursor);
if (cursor + size < max_size) cursor += size;
} else if (key == KEY_ALPHA) { } else if (key == KEY_ALPHA) {
swkbd = swkbd_alphabet; swkbd = swkbd_alphabet;
} else if (key == KEY_SPECIAL) { } else if (key == KEY_SPECIAL) {

View File

@ -476,6 +476,24 @@ u32 GetDrawStringHeight(const char* str) {
return height; return height;
} }
u32 GetCharSize(const char* str) {
const char *start = str;
do {
str++;
} while ((*str & 0xC0) == 0x80);
return str - start;
}
u32 GetPrevCharSize(const char* str) {
const char *start = str;
do {
str--;
} while ((*str & 0xC0) == 0x80);
return start - str;
}
u32 GetDrawStringWidth(const char* str) { u32 GetDrawStringWidth(const char* str) {
u32 width = 0; u32 width = 0;
char* old_lf = (char*) str; char* old_lf = (char*) str;
@ -994,7 +1012,7 @@ u32 ShowHotkeyPrompt(u32 n, const char** options, const u32* keys, const char *f
bool ShowInputPrompt(char* inputstr, u32 max_size, u32 resize, const char* alphabet, const char *format, va_list va) { bool ShowInputPrompt(char* inputstr, u32 max_size, u32 resize, const char* alphabet, const char *format, va_list va) {
const u32 alphabet_size = strnlen(alphabet, 256); const u32 alphabet_size = strnlen(alphabet, 256);
const u32 input_shown = 22; const u32 input_shown_length = 22;
const u32 fast_scroll = 4; const u32 fast_scroll = 4;
const u64 aprv_delay = 128; const u64 aprv_delay = 128;
@ -1033,25 +1051,43 @@ bool ShowInputPrompt(char* inputstr, u32 max_size, u32 resize, const char* alpha
while (true) { while (true) {
u32 inputstr_size = strnlen(inputstr, max_size - 1); u32 inputstr_size = strnlen(inputstr, max_size - 1);
if (cursor_s < scroll) scroll = cursor_s;
else if (cursor_s - scroll >= input_shown) scroll = cursor_s - input_shown + 1; if (cursor_s < scroll) {
while (scroll && (inputstr_size - scroll < input_shown)) scroll--; scroll = cursor_s;
DrawStringF(MAIN_SCREEN, x, y + str_height - 76, COLOR_STD_FONT, COLOR_STD_BG, "%c%-*.*s%c%-*.*s\n%-*.*s^%-*.*s", } else {
int scroll_adjust = -input_shown_length;
for (u32 i = scroll; i < cursor_s; i++) {
if (i >= inputstr_size || (inputstr[i] & 0xC0) != 0x80) scroll_adjust++;
}
for (int i = 0; i <= scroll_adjust; i++)
scroll += scroll >= inputstr_size ? 1 : GetCharSize(inputstr + scroll);
}
u32 input_shown_size = 0;
for (u32 i = 0; i < input_shown_length || (scroll + input_shown_size < inputstr_size && (inputstr[scroll + input_shown_size] & 0xC0) == 0x80); input_shown_size++) {
if (scroll + input_shown_size >= inputstr_size || (inputstr[scroll + input_shown_size] & 0xC0) != 0x80) i++;
}
u16 cpos = 0;
for (u16 i = scroll; i < cursor_s; i++) {
if (i >= inputstr_size || (inputstr[i] & 0xC0) != 0x80) cpos++;
}
DrawStringF(MAIN_SCREEN, x, y + str_height - 76, COLOR_STD_FONT, COLOR_STD_BG, "%c%-*.*s%c\n%-*.*s^%-*.*s",
(scroll) ? '<' : '|', (scroll) ? '<' : '|',
(inputstr_size > input_shown) ? input_shown : inputstr_size, input_shown_size,
(inputstr_size > input_shown) ? input_shown : inputstr_size, input_shown_size,
inputstr + scroll, (scroll > inputstr_size) ? "" : inputstr + scroll,
(inputstr_size - scroll > input_shown) ? '>' : '|', (inputstr_size - (s32) scroll > input_shown_size) ? '>' : '|',
(inputstr_size > input_shown) ? 0 : input_shown - inputstr_size, 1 + cpos,
(inputstr_size > input_shown) ? 0 : input_shown - inputstr_size, 1 + cpos,
"", "",
1 + cursor_s - scroll, input_shown_length - cpos,
1 + cursor_s - scroll, input_shown_length - cpos,
"",
input_shown - (cursor_s - scroll),
input_shown - (cursor_s - scroll),
"" ""
); );
if (cursor_a < 0) { if (cursor_a < 0) {
for (cursor_a = alphabet_size - 1; (cursor_a > 0) && (alphabet[cursor_a] != inputstr[cursor_s]); cursor_a--); for (cursor_a = alphabet_size - 1; (cursor_a > 0) && (alphabet[cursor_a] != inputstr[cursor_s]); cursor_a--);
} }
@ -1091,11 +1127,26 @@ bool ShowInputPrompt(char* inputstr, u32 max_size, u32 resize, const char* alpha
} }
} else if (pad_state & BUTTON_X) { } else if (pad_state & BUTTON_X) {
if (resize && (inputstr_size > resize)) { if (resize && (inputstr_size > resize)) {
char* inputfrom = inputstr + cursor_s - (cursor_s % resize) + resize; u32 char_index = 0;
char* inputto = inputstr + cursor_s - (cursor_s % resize); for(u32 i = 0; i < cursor_s; i++) {
if (i >= inputstr_size || (inputstr[i] & 0xC0) != 0x80) char_index++;
}
u32 to_index = char_index - (char_index % resize);
u32 from_index = to_index + resize;
char* inputto = inputstr + cursor_s;
for (u32 i = 0; i < char_index - to_index; i++) {
inputto -= GetPrevCharSize(inputto);
}
char* inputfrom = inputto;
for (u32 i = 0; i < from_index - to_index; i++) {
inputfrom += GetCharSize(inputfrom);
}
memmove(inputto, inputfrom, max_size - (inputfrom - inputstr)); memmove(inputto, inputfrom, max_size - (inputfrom - inputstr));
inputstr_size -= resize; inputstr_size -= inputfrom - inputto;
while (cursor_s >= inputstr_size) while (cursor_s >= inputstr_size || (inputstr[cursor_s] & 0xC0) == 0x80)
cursor_s--; cursor_s--;
cursor_a = -1; cursor_a = -1;
} else if (resize == 1) { } else if (resize == 1) {
@ -1112,18 +1163,29 @@ bool ShowInputPrompt(char* inputstr, u32 max_size, u32 resize, const char* alpha
cursor_a = 0; cursor_a = 0;
} }
} else if (pad_state & BUTTON_UP) { } else if (pad_state & BUTTON_UP) {
int size = GetCharSize(inputstr + cursor_s);
if(size > 1) {
memmove(inputstr + cursor_s, inputstr + cursor_s + size - 1, inputstr_size - cursor_s + size - 1);
}
cursor_a += (pad_state & BUTTON_R1) ? fast_scroll : 1; cursor_a += (pad_state & BUTTON_R1) ? fast_scroll : 1;
cursor_a = cursor_a % alphabet_size; cursor_a = cursor_a % alphabet_size;
inputstr[cursor_s] = alphabet[cursor_a]; inputstr[cursor_s] = alphabet[cursor_a];
} else if (pad_state & BUTTON_DOWN) { } else if (pad_state & BUTTON_DOWN) {
int size = GetCharSize(inputstr + cursor_s);
if(size > 1) {
memmove(inputstr + cursor_s, inputstr + cursor_s + size - 1, inputstr_size - cursor_s + size - 1);
}
cursor_a -= (pad_state & BUTTON_R1) ? fast_scroll : 1; cursor_a -= (pad_state & BUTTON_R1) ? fast_scroll : 1;
if (cursor_a < 0) cursor_a = alphabet_size + cursor_a; if (cursor_a < 0) cursor_a = alphabet_size + cursor_a;
inputstr[cursor_s] = alphabet[cursor_a]; inputstr[cursor_s] = alphabet[cursor_a];
} else if (pad_state & BUTTON_LEFT) { } else if (pad_state & BUTTON_LEFT) {
if (cursor_s > 0) cursor_s--; if (cursor_s > 0) cursor_s -= GetPrevCharSize(inputstr + cursor_s);
cursor_a = -1; cursor_a = -1;
} else if (pad_state & BUTTON_RIGHT) { } else if (pad_state & BUTTON_RIGHT) {
if (cursor_s < max_size - 2) cursor_s++; int size = cursor_s > inputstr_size ? 1 : GetCharSize(inputstr + cursor_s);
if (cursor_s + size < max_size - 1) cursor_s += size;
if (cursor_s >= inputstr_size) { if (cursor_s >= inputstr_size) {
memset(inputstr + cursor_s, alphabet[0], resize); memset(inputstr + cursor_s, alphabet[0], resize);
inputstr[cursor_s + resize] = '\0'; inputstr[cursor_s + resize] = '\0';

View File

@ -66,6 +66,9 @@ void DrawString(u16 *screen, const char *str, int x, int y, u32 color, u32 bgcol
void DrawStringF(u16 *screen, int x, int y, u32 color, u32 bgcolor, const char *format, ...); void DrawStringF(u16 *screen, int x, int y, u32 color, u32 bgcolor, const char *format, ...);
void DrawStringCenter(u16 *screen, u32 color, u32 bgcolor, const char *format, ...); void DrawStringCenter(u16 *screen, u32 color, u32 bgcolor, const char *format, ...);
u32 GetCharSize(const char* str);
u32 GetPrevCharSize(const char* str);
u32 GetDrawStringHeight(const char* str); u32 GetDrawStringHeight(const char* str);
u32 GetDrawStringWidth(const char* str); u32 GetDrawStringWidth(const char* str);
u32 GetFontWidth(void); u32 GetFontWidth(void);