Fix FS#10597: Loadable keyboard layout rendered incorrectly.

Also fix out of bounds access to kbd_buf.
Reset cursor position in keyboard when loading new virtual keyboard for the case size is different from previous one.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@22892 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Teruaki Kawashima 2009-10-03 13:53:49 +00:00
parent c78e9de35a
commit ccf2078150

View file

@ -98,6 +98,7 @@ struct keyboard_parameters
int nchars; int nchars;
int font_w; int font_w;
int font_h; int font_h;
int text_w;
struct font* font; struct font* font;
int curfont; int curfont;
int main_x; int main_x;
@ -144,6 +145,12 @@ int load_kbd(unsigned char* filename)
int i = 0; int i = 0;
unsigned char buf[4]; unsigned char buf[4];
FOR_NB_SCREENS(l)
{
struct keyboard_parameters *pm = &kbd_param[l];
pm->x = pm->y = pm->page = 0;
}
if (filename == NULL) if (filename == NULL)
{ {
kbd_loaded = false; kbd_loaded = false;
@ -159,6 +166,7 @@ int load_kbd(unsigned char* filename)
/* check how many bytes to read for this character */ /* check how many bytes to read for this character */
static const unsigned char sizes[4] = { 0x80, 0xe0, 0xf0, 0xf5 }; static const unsigned char sizes[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
size_t count; size_t count;
unsigned short ch;
for (count = 0; count < ARRAYLEN(sizes); count++) for (count = 0; count < ARRAYLEN(sizes); count++)
{ {
@ -176,11 +184,11 @@ int load_kbd(unsigned char* filename)
return 1; return 1;
} }
utf8decode(buf, &ch);
FOR_NB_SCREENS(l) FOR_NB_SCREENS(l)
utf8decode(buf, &kbd_param[l].kbd_buf[i]); kbd_param[l].kbd_buf[i] = ch;
if (kbd_param[0].kbd_buf[i] != 0xFEFF && if (ch != 0xFEFF && ch != '\r') /*skip BOM & carriage returns */
kbd_param[0].kbd_buf[i] != '\r') /*skip BOM & carriage returns */
{ {
i++; i++;
} }
@ -276,9 +284,10 @@ static void kbd_delchar(unsigned char* text, int* editpos)
} }
/* Lookup k value based on state of param (pm) */ /* Lookup k value based on state of param (pm) */
static int get_param_k(const struct keyboard_parameters *pm) static unsigned short get_kbd_ch(const struct keyboard_parameters *pm)
{ {
return (pm->page*pm->lines + pm->y)*pm->max_chars + pm->x; int k = (pm->page*pm->lines + pm->y)*pm->max_chars + pm->x;
return (k < pm->nchars)? pm->kbd_buf[k]: ' ';
} }
int kbd_input(char* text, int buflen) int kbd_input(char* text, int buflen)
@ -291,7 +300,6 @@ int kbd_input(char* text, int buflen)
struct keyboard_parameters * const param = kbd_param; struct keyboard_parameters * const param = kbd_param;
#endif #endif
int l; /* screen loop variable */ int l; /* screen loop variable */
int text_w = 0;
int editpos; /* Edit position on all screens */ int editpos; /* Edit position on all screens */
const int statusbar_size = 0; const int statusbar_size = 0;
unsigned short ch; unsigned short ch;
@ -405,11 +413,14 @@ int kbd_input(char* text, int buflen)
pm->font_w = 0; /* reset font width */ pm->font_w = 0; /* reset font width */
/* find max width of keyboard glyphs */ /* find max width of keyboard glyphs */
for (i = 0; i < pm->nchars; i++) for (i = 0; i < pm->nchars; i++)
{
if (pm->kbd_buf[i] != '\n')
{ {
w = font_get_width(pm->font, pm->kbd_buf[i]); w = font_get_width(pm->font, pm->kbd_buf[i]);
if ( w > pm->font_w ) if ( w > pm->font_w )
pm->font_w = w; pm->font_w = w;
} }
}
/* Since we're going to be adding spaces, make sure that we check /* Since we're going to be adding spaces, make sure that we check
* their width too */ * their width too */
@ -424,16 +435,17 @@ int kbd_input(char* text, int buflen)
struct screen *sc = &screens[l]; struct screen *sc = &screens[l];
int i = 0; int i = 0;
pm->max_chars = sc->getwidth() / pm->font_w;
/* Pad lines with spaces */ /* Pad lines with spaces */
while (i < pm->nchars) while (i < pm->nchars)
{ {
if (pm->kbd_buf[i] == '\n') if (pm->kbd_buf[i] == '\n')
{ {
int k = sc->getwidth() / pm->font_w int k = pm->max_chars - i % ( pm->max_chars ) - 1;
- i % ( sc->getwidth() / pm->font_w ) - 1;
int j; int j;
if (k == sc->getwidth() / pm->font_w - 1) if (k == pm->max_chars - 1)
{ {
pm->nchars--; pm->nchars--;
@ -471,27 +483,24 @@ int kbd_input(char* text, int buflen)
} }
/* Find max width for text string */ /* Find max width for text string */
utf8 = text;
FOR_NB_SCREENS(l) FOR_NB_SCREENS(l)
{ {
struct keyboard_parameters *pm = &param[l]; struct keyboard_parameters *pm = &param[l];
struct screen *sc = &screens[l]; struct screen *sc = &screens[l];
text_w = pm->font_w; pm->text_w = pm->font_w;
utf8 = text;
while (*utf8) while (*utf8)
{ {
int w = font_get_width(pm->font, ch); int w;
utf8 = (unsigned char*)utf8decode(utf8, &ch); utf8 = (unsigned char*)utf8decode(utf8, &ch);
w = font_get_width(pm->font, ch);
if (w > text_w) if (w > pm->text_w)
text_w = w; pm->text_w = w;
} }
pm->max_chars_text = sc->getwidth() / text_w - 2; pm->max_chars_text = sc->getwidth() / pm->text_w - 2;
/* Calculate keyboard grid size */
pm->max_chars = sc->getwidth() / pm->font_w;
if (!kbd_loaded) if (!kbd_loaded)
{ {
@ -644,6 +653,7 @@ int kbd_input(char* text, int buflen)
struct keyboard_parameters *pm = &param[l]; struct keyboard_parameters *pm = &param[l];
struct screen *sc = &screens[l]; struct screen *sc = &screens[l];
int i = 0, j = 0; int i = 0, j = 0;
int text_w = pm->text_w;
/* Clear text area one pixel above separator line so any overdraw /* Clear text area one pixel above separator line so any overdraw
doesn't collide */ doesn't collide */
@ -662,8 +672,6 @@ int kbd_input(char* text, int buflen)
pm->leftpos = editpos - pm->curpos; pm->leftpos = editpos - pm->curpos;
utf8 = text + utf8seek(text, pm->leftpos); utf8 = text + utf8seek(text, pm->leftpos);
text_w = pm->font_w;
while (*utf8 && i < pm->max_chars_text) while (*utf8 && i < pm->max_chars_text)
{ {
outline[j++] = *utf8++; outline[j++] = *utf8++;
@ -780,7 +788,6 @@ int kbd_input(char* text, int buflen)
case ACTION_KBD_PAGE_FLIP: case ACTION_KBD_PAGE_FLIP:
{ {
int k;
#ifdef KBD_MORSE_INPUT #ifdef KBD_MORSE_INPUT
if (morse_mode) if (morse_mode)
break; break;
@ -788,8 +795,8 @@ int kbd_input(char* text, int buflen)
if (++pm->page >= pm->pages) if (++pm->page >= pm->pages)
pm->page = 0; pm->page = 0;
k = get_param_k(pm); ch = get_kbd_ch(pm);
kbd_spellchar(pm->kbd_buf[k]); kbd_spellchar(ch);
break; break;
} }
@ -843,7 +850,6 @@ int kbd_input(char* text, int buflen)
else else
#endif /* KBD_MODES */ #endif /* KBD_MODES */
{ {
int k;
#ifdef KBD_MORSE_INPUT #ifdef KBD_MORSE_INPUT
if (morse_mode) if (morse_mode)
break; break;
@ -858,8 +864,8 @@ int kbd_input(char* text, int buflen)
pm->x = 0; pm->x = 0;
} }
k = get_param_k(pm); ch = get_kbd_ch(pm);
kbd_spellchar(pm->kbd_buf[k]); kbd_spellchar(ch);
} }
break; break;
@ -888,7 +894,6 @@ int kbd_input(char* text, int buflen)
else else
#endif /* KBD_MODES */ #endif /* KBD_MODES */
{ {
int k;
#ifdef KBD_MORSE_INPUT #ifdef KBD_MORSE_INPUT
if (morse_mode) if (morse_mode)
break; break;
@ -903,8 +908,8 @@ int kbd_input(char* text, int buflen)
pm->x = pm->max_chars - 1; pm->x = pm->max_chars - 1;
} }
k = get_param_k(pm); ch = get_kbd_ch(pm);
kbd_spellchar(pm->kbd_buf[k]); kbd_spellchar(ch);
} }
break; break;
@ -946,8 +951,8 @@ int kbd_input(char* text, int buflen)
if (!pm->line_edit) if (!pm->line_edit)
#endif #endif
{ {
int k = get_param_k(pm); ch = get_kbd_ch(pm);
kbd_spellchar(pm->kbd_buf[k]); kbd_spellchar(ch);
} }
break; break;
@ -989,8 +994,8 @@ int kbd_input(char* text, int buflen)
if (!pm->line_edit) if (!pm->line_edit)
#endif #endif
{ {
int k = get_param_k(pm); ch = get_kbd_ch(pm);
kbd_spellchar(pm->kbd_buf[k]); kbd_spellchar(ch);
} }
break; break;
@ -1061,8 +1066,7 @@ int kbd_input(char* text, int buflen)
#endif /* KBD_MODES */ #endif /* KBD_MODES */
{ {
/* find input char */ /* find input char */
int k = get_param_k(pm); ch = get_kbd_ch(pm);
ch = (k < pm->nchars) ? pm->kbd_buf[k] : ' ';
/* check for hangul input */ /* check for hangul input */
if (ch >= 0x3131 && ch <= 0x3163) if (ch >= 0x3131 && ch <= 0x3163)