summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/filetree.c9
-rw-r--r--apps/keyboard.h4
-rw-r--r--apps/lang/english.lang11
-rw-r--r--apps/recorder/icons.c1
-rw-r--r--apps/recorder/icons.h1
-rw-r--r--apps/recorder/keyboard.c639
-rw-r--r--apps/settings.c34
-rw-r--r--apps/settings.h4
-rw-r--r--apps/tree.c1
-rw-r--r--apps/tree.h1
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/export/hangul.h23
-rw-r--r--firmware/hangul.c101
13 files changed, 639 insertions, 191 deletions
diff --git a/apps/filetree.c b/apps/filetree.c
index bbe56e119c..7b4f5e7ed8 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -41,6 +41,9 @@
41#include "dircache.h" 41#include "dircache.h"
42#include "splash.h" 42#include "splash.h"
43#include "yesno.h" 43#include "yesno.h"
44#ifdef HAVE_LCD_BITMAP
45#include "keyboard.h"
46#endif
44 47
45#ifndef SIMULATOR 48#ifndef SIMULATOR
46static int boot_size = 0; 49static int boot_size = 0;
@@ -462,6 +465,12 @@ int ft_enter(struct tree_context* c)
462 font_load(buf); 465 font_load(buf);
463 set_file(buf, (char *)global_settings.font_file, MAX_FILENAME); 466 set_file(buf, (char *)global_settings.font_file, MAX_FILENAME);
464 break; 467 break;
468
469 case TREE_ATTR_KBD:
470 if (!load_kbd(buf))
471 gui_syncsplash(HZ, true, str(LANG_KEYBOARD_LOADED));
472 set_file(buf, (char *)global_settings.kbd_file, MAX_FILENAME);
473 break;
465#endif 474#endif
466 475
467#ifndef SIMULATOR 476#ifndef SIMULATOR
diff --git a/apps/keyboard.h b/apps/keyboard.h
index fa1e11e0ce..3ba2822e36 100644
--- a/apps/keyboard.h
+++ b/apps/keyboard.h
@@ -21,4 +21,8 @@
21 21
22int kbd_input(char* buffer, int buflen); 22int kbd_input(char* buffer, int buflen);
23 23
24#ifdef HAVE_LCD_BITMAP
25int load_kbd(unsigned char* filename);
26#endif
27
24#endif 28#endif
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index c239b9cdd3..e591b46b9f 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -3887,3 +3887,14 @@ eng: "Precut"
3887voice: "Pre-cut" 3887voice: "Pre-cut"
3888new: 3888new:
3889 3889
3890id: LANG_KEYBOARD_LOADED
3891desc: shown when a keyboard has been loaded from the dir browser
3892eng: "New Keyboard"
3893voice: ""
3894new:
3895
3896id: VOICE_EXT_KBD
3897desc: spoken only, for file extension
3898eng: ""
3899voice: "keyboard"
3900new:
diff --git a/apps/recorder/icons.c b/apps/recorder/icons.c
index 6a0291ae5e..4b6df725f9 100644
--- a/apps/recorder/icons.c
+++ b/apps/recorder/icons.c
@@ -49,6 +49,7 @@ const unsigned char bitmap_icons_6x8[][6] =
49 { 0xff, 0x81, 0xaf, 0xaa, 0x8c, 0xf8 }, /* Bookmark file */ 49 { 0xff, 0x81, 0xaf, 0xaa, 0x8c, 0xf8 }, /* Bookmark file */
50 { 0x77, 0x55, 0x55, 0x55, 0x55, 0x77 }, /* Queued Item */ 50 { 0x77, 0x55, 0x55, 0x55, 0x55, 0x77 }, /* Queued Item */
51 { 0x3e, 0x41, 0x3e, 0x1c, 0x1c, 0x08 }, /* Moving Item */ 51 { 0x3e, 0x41, 0x3e, 0x1c, 0x1c, 0x08 }, /* Moving Item */
52 { 0x7f, 0x7f, 0x1c, 0x3e, 0x77, 0x63 }, /* Keyboard file */
52}; 53};
53 54
54const unsigned char bitmap_icons_7x8[][7] = 55const unsigned char bitmap_icons_7x8[][7] =
diff --git a/apps/recorder/icons.h b/apps/recorder/icons.h
index 62ed73aeac..15747edeeb 100644
--- a/apps/recorder/icons.h
+++ b/apps/recorder/icons.h
@@ -56,6 +56,7 @@ enum icons_6x8 {
56 Icon_Bookmark, 56 Icon_Bookmark,
57 Icon_Queued, 57 Icon_Queued,
58 Icon_Moving, 58 Icon_Moving,
59 Icon_Keyboard,
59 Icon6x8Last 60 Icon6x8Last
60}; 61};
61 62
diff --git a/apps/recorder/keyboard.c b/apps/recorder/keyboard.c
index cb982e38e6..47deb3a5b9 100644
--- a/apps/recorder/keyboard.c
+++ b/apps/recorder/keyboard.c
@@ -33,19 +33,28 @@
33#include "rbunicode.h" 33#include "rbunicode.h"
34#include "buttonbar.h" 34#include "buttonbar.h"
35#include "logf.h" 35#include "logf.h"
36#include "icons.h"
37#include "file.h"
38#include "hangul.h"
36 39
37#define KEYBOARD_MARGIN 3 40#ifndef O_BINARY
38 41#define O_BINARY 0
39#if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 96) 42#endif
40#define KEYBOARD_LINES 8
41#define KEYBOARD_PAGES 1
42 43
44#if CONFIG_KEYPAD == RECORDER_PAD
45#define BUTTONBAR_HEIGHT 8
43#else 46#else
44#define KEYBOARD_LINES 4 47#define BUTTONBAR_HEIGHT 0
45#define KEYBOARD_PAGES 3 48#endif
46 49
50#if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 96)
51#define DEFAULT_LINES 8
52#else
53#define DEFAULT_LINES 4
47#endif 54#endif
48 55
56#define DEFAULT_MARGIN 6
57#define KBD_BUF_SIZE 500
49 58
50#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ 59#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
51 (CONFIG_KEYPAD == IRIVER_H300_PAD) 60 (CONFIG_KEYPAD == IRIVER_H300_PAD)
@@ -61,7 +70,7 @@
61#define KBD_RIGHT BUTTON_RIGHT 70#define KBD_RIGHT BUTTON_RIGHT
62#define KBD_UP BUTTON_UP 71#define KBD_UP BUTTON_UP
63#define KBD_DOWN BUTTON_DOWN 72#define KBD_DOWN BUTTON_DOWN
64#define HAVE_MORSE_INPUT 73#define KBD_MORSE_INPUT (BUTTON_ON | BUTTON_MODE)
65 74
66#elif CONFIG_KEYPAD == RECORDER_PAD 75#elif CONFIG_KEYPAD == RECORDER_PAD
67#define KBD_CURSOR_RIGHT (BUTTON_ON | BUTTON_RIGHT) 76#define KBD_CURSOR_RIGHT (BUTTON_ON | BUTTON_RIGHT)
@@ -172,39 +181,39 @@
172 181
173#endif 182#endif
174 183
175#if KEYBOARD_PAGES == 1 184#if (LCD_WIDTH >= 160) && (LCD_HEIGHT >= 96)
176static const char * const kbdpages[KEYBOARD_PAGES][KEYBOARD_LINES] = { 185static const unsigned char * default_kbd =
177 { "ABCDEFG abcdefg !?\" @#$%+'", 186 "ABCDEFG abcdefg !?\" @#$%+'\n"
178 "HIJKLMN hijklmn 789 &_()-`", 187 "HIJKLMN hijklmn 789 &_()-`\n"
179 "OPQRSTU opqrstu 456 §|{}/<", 188 "OPQRSTU opqrstu 456 §|{}/<\n"
180 "VWXYZ., vwxyz.,0123 ~=[]*>", 189 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
181 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®", 190 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
182 "àáâãäåæ ìíîï èéêë «»°ºª¹²³", 191 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
183 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·", 192 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
184 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨ " }, 193 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨";
185};
186
187#else 194#else
188static const char * const kbdpages[KEYBOARD_PAGES][KEYBOARD_LINES] = { 195static const unsigned char * default_kbd =
189 { "ABCDEFG !?\" @#$%+'", 196 "ABCDEFG !?\" @#$%+'\n"
190 "HIJKLMN 789 &_()-`", 197 "HIJKLMN 789 &_()-`\n"
191 "OPQRSTU 456 §|{}/<", 198 "OPQRSTU 456 §|{}/<\n"
192 "VWXYZ.,0123 ~=[]*>" }, 199 "VWXYZ.,0123 ~=[]*>\n"
193 200
194 { "abcdefg ¢£¤¥¦§©®¬", 201 "abcdefg ¢£¤¥¦§©®¬\n"
195 "hijklmn «»°ºª¹²³¶", 202 "hijklmn «»°ºª¹²³¶\n"
196 "opqrstu ¯±×÷¡¿µ·¨", 203 "opqrstu ¯±×÷¡¿µ·¨\n"
197 "vwxyz., ¼½¾ " }, 204 "vwxyz., ¼½¾ \n"
198
199 { "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË",
200 "àáâãäåæ ìíîï èéêë",
201 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ",
202 "òóôõöø çðþýÿ ùúûü" },
203};
204 205
206 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
207 "àáâãäåæ ìíîï èéêë\n"
208 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
209 "òóôõöø çðþýÿ ùúûü";
205#endif 210#endif
206 211
207#ifdef HAVE_MORSE_INPUT 212static unsigned short kbd_buf[KBD_BUF_SIZE];
213static bool kbd_loaded = false;
214static int nchars = 0;
215
216#ifdef KBD_MORSE_INPUT
208/* FIXME: We should put this to a configuration file. */ 217/* FIXME: We should put this to a configuration file. */
209static const char *morse_alphabets = 218static const char *morse_alphabets =
210 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ "; 219 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
@@ -217,37 +226,139 @@ static const unsigned char morse_codes[] = {
217static bool morse_mode = false; 226static bool morse_mode = false;
218#endif 227#endif
219 228
229/* Loads a custom keyboard into memory
230 call with NULL to reset keyboard */
231int load_kbd(unsigned char* filename)
232{
233 int fd, count;
234 int i = 0;
235 unsigned char buf[4];
236
237 if (filename == NULL) {
238 kbd_loaded = false;
239 return 0;
240 }
241
242 fd = open(filename, O_RDONLY|O_BINARY);
243 if (fd < 0)
244 return 1;
245
246 while (read(fd, buf, 1) == 1 && i < KBD_BUF_SIZE) {
247 /* check how many bytes to read */
248 if (buf[0] < 0x80) {
249 count = 0;
250 } else if (buf[0] < 0xe0) {
251 count = 1;
252 } else if (buf[0] < 0xf0) {
253 count = 2;
254 } else if (buf[0] < 0xf5) {
255 count = 3;
256 } else {
257 /* Invalid size. */
258 continue;
259 }
260
261 if (read(fd, &buf[1], count) != count) {
262 close(fd);
263 kbd_loaded = false;
264 return 1;
265 }
266
267 utf8decode(buf, &kbd_buf[i]);
268 if (kbd_buf[i] != 0xFEFF && kbd_buf[i] != '\n' &&
269 kbd_buf[i] != '\r') /*skip BOM & newlines */
270 i++;
271 }
272
273 close(fd);
274 kbd_loaded = true;
275 nchars = i;
276 return 0;
277
278}
279
220/* helper function to spell a char if voice UI is enabled */ 280/* helper function to spell a char if voice UI is enabled */
221static void kbd_spellchar(char c) 281static void kbd_spellchar(unsigned short c)
222{ 282{
223 static char spell_char[2] = "\0\0"; /* store char to pass to talk_spell */ 283 static char spell_char[2] = "\0\0"; /* store char to pass to talk_spell */
224 284
225 if (global_settings.talk_menu) /* voice UI? */ 285 if (global_settings.talk_menu && c < 128) /* voice UI? */
226 { 286 {
227 spell_char[0] = c; 287 spell_char[0] = (char)c;
228 talk_spell(spell_char, false); 288 talk_spell(spell_char, false);
229 } 289 }
230} 290}
231 291
292void kbd_inschar(unsigned char* text, int buflen, int* editpos, unsigned short ch)
293{
294 int i, j, k, len;
295 unsigned char tmp[4];
296 unsigned char* utf8;
297
298 len = strlen(text);
299 k = utf8length(text);
300 utf8 = utf8encode(ch, tmp);
301 j = (long)utf8 - (long)tmp;
302
303 if (len + j < buflen)
304 {
305 for (i = len+j; k >= *editpos; i--) {
306 text[i] = text[i-j];
307 if ((text[i] & MASK) != COMP)
308 k--;
309 }
310 while (j--)
311 text[i--] = tmp[j];
312 (*editpos)++;
313 }
314 return;
315}
316
317void kbd_delchar(unsigned char* text, int* editpos)
318{
319 int i = 0;
320 unsigned char* utf8;
321
322 if (*editpos > 0)
323 {
324 utf8 = text + utf8seek(text, *editpos);
325 do {
326 i++;
327 utf8--;
328 } while ((*utf8 & MASK) == COMP);
329 while (utf8[i]) {
330 *utf8 = utf8[i];
331 utf8++;
332 }
333 *utf8 = 0;
334 (*editpos)--;
335 }
336
337 return;
338}
339
232int kbd_input(char* text, int buflen) 340int kbd_input(char* text, int buflen)
233{ 341{
234 bool done = false; 342 bool done = false;
235#if defined(KBD_PAGE_FLIP) || (KEYBOARD_PAGES > 1)
236 int page = 0; 343 int page = 0;
237#endif 344 int font_w = 0, font_h = 0, text_w = 0;
238 int font_w = 0, font_h = 0, i, j; 345 int i = 0, j, k, w;
239 int x = 0, y = 0; 346 int x = 0, y = 0;
240 int main_x, main_y, max_chars; 347 int main_x, main_y, max_chars, max_chars_text;
241 int status_y1, status_y2; 348 int len_utf8, c = 0;
242 int len, len_utf8, c = 0;
243 int editpos, curpos, leftpos; 349 int editpos, curpos, leftpos;
350 int lines, pages, keyboard_margin;
351 int curfont;
352 int statusbar_size = global_settings.statusbar ? STATUSBAR_HEIGHT : 0;
353 unsigned short ch, tmp, hlead = 0, hvowel = 0, htail = 0;
354 bool hangul = false;
244 bool redraw = true; 355 bool redraw = true;
245 unsigned char *utf8; 356 unsigned char *utf8;
246 const char * const *line; 357 const unsigned char *p;
247#ifdef HAVE_MORSE_INPUT 358#ifdef KBD_MORSE_INPUT
248 bool morse_reading = false; 359 bool morse_reading = false;
249 unsigned char morse_code = 0; 360 unsigned char morse_code = 0;
250 int morse_tick = 0, morse_len; 361 int morse_tick = 0, morse_len, old_main_y;
251 char buf[2]; 362 char buf[2];
252#endif 363#endif
253#ifdef KBD_MODES 364#ifdef KBD_MODES
@@ -255,7 +366,7 @@ int kbd_input(char* text, int buflen)
255#endif 366#endif
256 367
257 char outline[256]; 368 char outline[256];
258 struct font* font = font_get(FONT_SYSFIXED); 369 struct font* font;
259 int button, lastbutton = 0; 370 int button, lastbutton = 0;
260#ifdef HAS_BUTTONBAR 371#ifdef HAS_BUTTONBAR
261 struct gui_buttonbar buttonbar; 372 struct gui_buttonbar buttonbar;
@@ -264,44 +375,103 @@ int kbd_input(char* text, int buflen)
264 gui_buttonbar_init(&buttonbar); 375 gui_buttonbar_init(&buttonbar);
265 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) ); 376 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
266#endif 377#endif
267 lcd_setfont(FONT_SYSFIXED); 378
268 font_w = font->maxwidth; 379 if (!kbd_loaded) {
380 curfont = FONT_SYSFIXED;
381 p = default_kbd;
382 while (*p != 0) {
383 p = utf8decode(p, &kbd_buf[i]);
384 if (kbd_buf[i] == '\n')
385 while (i % (LCD_WIDTH/6))
386 kbd_buf[i++] = ' ';
387 else
388 i++;
389 }
390 nchars = i;
391 }
392 else
393 curfont = FONT_UI;
394
395 font = font_get(curfont);
269 font_h = font->height; 396 font_h = font->height;
270 397
271#ifdef HAVE_MORSE_INPUT 398 /* check if FONT_UI fits the screen */
399 if (2*font_h+3+statusbar_size + BUTTONBAR_HEIGHT > LCD_HEIGHT) {
400 font = font_get(FONT_SYSFIXED);
401 font_h = font->height;
402 curfont = FONT_SYSFIXED;
403 }
404
405 lcd_setfont(curfont);
406
407 /* find max width of keyboard glyphs */
408 for (i=0; i<nchars; i++) {
409 w = font_get_width(font, kbd_buf[i]);
410 if (w > font_w)
411 font_w = w;
412 }
413
414 /* find max width for text string */
415 utf8 = text;
416 text_w = font_w;
417 while (*utf8) {
418 utf8 = (unsigned char*)utf8decode(utf8, &ch);
419 w = font_get_width(font, ch);
420 if (w > text_w)
421 text_w = w;
422 }
423 max_chars_text = LCD_WIDTH / text_w - 2;
424
425 /* calculate keyboard grid size */
426 max_chars = LCD_WIDTH / font_w;
427 if (!kbd_loaded) {
428 lines = DEFAULT_LINES;
429 keyboard_margin = DEFAULT_MARGIN;
430 } else {
431 lines = (LCD_HEIGHT - BUTTONBAR_HEIGHT - statusbar_size) / font_h - 1;
432 keyboard_margin = LCD_HEIGHT - BUTTONBAR_HEIGHT - statusbar_size - (lines+1)*font_h;
433 if (keyboard_margin < 3) {
434 lines--;
435 keyboard_margin += font_h;
436 }
437 if (keyboard_margin > 6)
438 keyboard_margin = 6;
439 }
440
441 pages = (nchars + (lines*max_chars-1))/(lines*max_chars);
442 if (pages == 1 && kbd_loaded)
443 lines = (nchars + max_chars - 1) / max_chars;
444
445 main_y = font_h*lines + keyboard_margin + statusbar_size;
446 main_x = 0;
447 keyboard_margin -= keyboard_margin/2;
448
449#ifdef KBD_MORSE_INPUT
450 old_main_y = main_y;
272 if (morse_mode) 451 if (morse_mode)
273 main_y = LCD_HEIGHT - font_h; 452 main_y = LCD_HEIGHT - font_h;
274 else
275#endif 453#endif
276 main_y = (KEYBOARD_LINES + 1) * font_h + (2*KEYBOARD_MARGIN);
277 main_x = 0;
278 status_y1 = LCD_HEIGHT - font_h;
279 status_y2 = LCD_HEIGHT;
280 454
281 editpos = utf8length(text); 455 editpos = utf8length(text);
282
283 max_chars = LCD_WIDTH / font_w - 2; /* leave room for < and > */
284 line = kbdpages[0];
285 456
286 if (global_settings.talk_menu) /* voice UI? */ 457 if (global_settings.talk_menu) /* voice UI? */
287 talk_spell(text, true); /* spell initial text */ 458 talk_spell(text, true); /* spell initial text */
288 459
289 while(!done) 460 while(!done)
290 { 461 {
291 len = strlen(text);
292 len_utf8 = utf8length(text); 462 len_utf8 = utf8length(text);
293 463
294 if(redraw) 464 if(redraw)
295 { 465 {
296 lcd_clear_display(); 466 lcd_clear_display();
297 467
298 lcd_setfont(FONT_SYSFIXED); 468#ifdef KBD_MORSE_INPUT
299
300#ifdef HAVE_MORSE_INPUT
301 if (morse_mode) 469 if (morse_mode)
302 { 470 {
471 lcd_setfont(FONT_SYSFIXED); /* Draw morse code screen with sysfont */
472 w = 6; /* sysfixed font width */
303 x = 0; 473 x = 0;
304 y = font_h; 474 y = statusbar_size;
305 buf[1] = '\0'; 475 buf[1] = '\0';
306 /* Draw morse code table with code descriptions. */ 476 /* Draw morse code table with code descriptions. */
307 for (i = 0; morse_alphabets[i] != '\0'; i++) 477 for (i = 0; morse_alphabets[i] != '\0'; i++)
@@ -312,7 +482,7 @@ int kbd_input(char* text, int buflen)
312 for (j = 0; (morse_codes[i] >> j) > 0x01; j++) ; 482 for (j = 0; (morse_codes[i] >> j) > 0x01; j++) ;
313 morse_len = j; 483 morse_len = j;
314 484
315 x += font_w + 3; 485 x += w + 3;
316 for (j = 0; j < morse_len; j++) 486 for (j = 0; j < morse_len; j++)
317 { 487 {
318 if ((morse_codes[i] >> (morse_len-j-1)) & 0x01) 488 if ((morse_codes[i] >> (morse_len-j-1)) & 0x01)
@@ -321,11 +491,11 @@ int kbd_input(char* text, int buflen)
321 lcd_fillrect(x + j*4, y + 3, 1, 2); 491 lcd_fillrect(x + j*4, y + 3, 1, 2);
322 } 492 }
323 493
324 x += font_w * 5 - 3; 494 x += w * 5 - 3;
325 if (x >= LCD_WIDTH - (font_w*6)) 495 if (x >= LCD_WIDTH - (w*6))
326 { 496 {
327 x = 0; 497 x = 0;
328 y += font_h; 498 y += 8; /* sysfixed font height */
329 } 499 }
330 } 500 }
331 } 501 }
@@ -333,50 +503,67 @@ int kbd_input(char* text, int buflen)
333#endif 503#endif
334 { 504 {
335 /* draw page */ 505 /* draw page */
336 for (i=0; i < KEYBOARD_LINES; i++) 506 lcd_setfont(curfont);
337 lcd_putsxy(0, 8+i * font_h, line[i]); 507 k = page*max_chars*lines;
338 508 for (i=j=0; j < lines && k < nchars; k++) {
509 utf8 = utf8encode(kbd_buf[k], outline);
510 *utf8 = 0;
511 lcd_getstringsize(outline, &w, NULL);
512 lcd_putsxy(i*font_w + (font_w-w)/2, j*font_h + statusbar_size, outline);
513 if (++i == max_chars) {
514 i = 0;
515 j++;
516 }
517 }
339 } 518 }
340 519
341 /* separator */ 520 /* separator */
342 lcd_hline(0, LCD_WIDTH - 1, main_y - KEYBOARD_MARGIN); 521 lcd_hline(0, LCD_WIDTH - 1, main_y - keyboard_margin);
343 522
344 /* write out the text */ 523 /* write out the text */
345 curpos = MIN(editpos, max_chars - MIN(len_utf8 - editpos, 2)); 524 lcd_setfont(curfont);
525 i=j=0;
526 curpos = MIN(editpos, max_chars_text - MIN(len_utf8 - editpos, 2));
346 leftpos = editpos - curpos; 527 leftpos = editpos - curpos;
347 utf8 = text + utf8seek(text, leftpos); 528 utf8 = text + utf8seek(text, leftpos);
348 i=j=0; 529
349 while (*utf8 && i < max_chars) { 530 while (*utf8 && i < max_chars_text) {
350 outline[j++] = *utf8++; 531 outline[j++] = *utf8++;
351 if ((*utf8 & MASK) != COMP) 532 if ((*utf8 & MASK) != COMP) {
533 outline[j] = 0;
534 j=0;
352 i++; 535 i++;
536 lcd_getstringsize(outline, &w, NULL);
537 lcd_putsxy(i*text_w + (text_w-w)/2, main_y, outline);
538 }
539 }
540
541 if (leftpos) {
542 lcd_getstringsize("<", &w, NULL);
543 lcd_putsxy(text_w - w, main_y, "<");
353 } 544 }
354 outline[j] = 0; 545 if (len_utf8 - leftpos > max_chars_text)
355 546 lcd_putsxy(LCD_WIDTH - text_w, main_y, ">");
356 lcd_putsxy(font_w, main_y, outline); 547
357
358 if (leftpos)
359 lcd_putsxy(0, main_y, "<");
360 if (len_utf8 - leftpos > max_chars)
361 lcd_putsxy(LCD_WIDTH - font_w, main_y, ">");
362
363 /* cursor */ 548 /* cursor */
364 i = (curpos + 1) * font_w; 549 i = (curpos + 1) * text_w;
365 lcd_vline(i, main_y, main_y + font_h); 550 lcd_vline(i, main_y, main_y + font_h);
366 551 if (hangul) /* draw underbar */
552 lcd_hline(curpos*text_w, (curpos+1)*text_w, main_y+font_h-1);
553
367#ifdef HAS_BUTTONBAR 554#ifdef HAS_BUTTONBAR
368 /* draw the status bar */ 555 /* draw the status bar */
369 gui_buttonbar_set(&buttonbar, "Shift", "OK", "Del"); 556 gui_buttonbar_set(&buttonbar, "Shift", "OK", "Del");
370 gui_buttonbar_draw(&buttonbar); 557 gui_buttonbar_draw(&buttonbar);
371#endif 558#endif
372 559
373#ifdef KBD_MODES 560#ifdef KBD_MODES
374 if (!line_edit) 561 if (!line_edit)
375#endif 562#endif
376 { 563 {
377 /* highlight the key that has focus */ 564 /* highlight the key that has focus */
378 lcd_set_drawmode(DRMODE_COMPLEMENT); 565 lcd_set_drawmode(DRMODE_COMPLEMENT);
379 lcd_fillrect(font_w * x, 8 + font_h * y, font_w, font_h); 566 lcd_fillrect(font_w * x, statusbar_size + font_h * y, font_w, font_h);
380 lcd_set_drawmode(DRMODE_SOLID); 567 lcd_set_drawmode(DRMODE_SOLID);
381 } 568 }
382 569
@@ -388,7 +575,7 @@ int kbd_input(char* text, int buflen)
388 redraw = true; 575 redraw = true;
389 576
390 button = button_get_w_tmo(HZ/2); 577 button = button_get_w_tmo(HZ/2);
391#ifdef HAVE_MORSE_INPUT 578#ifdef KBD_MORSE_INPUT
392 if (morse_mode) 579 if (morse_mode)
393 { 580 {
394 /* Remap some buttons for morse mode. */ 581 /* Remap some buttons for morse mode. */
@@ -411,40 +598,43 @@ int kbd_input(char* text, int buflen)
411 598
412#if defined(KBD_PAGE_FLIP) 599#if defined(KBD_PAGE_FLIP)
413 case KBD_PAGE_FLIP: 600 case KBD_PAGE_FLIP:
414#ifdef HAVE_MORSE_INPUT 601#ifdef KBD_MORSE_INPUT
415 if (morse_mode) 602 if (morse_mode)
416 { 603 break;
417 main_y = (KEYBOARD_LINES + 1) * font_h + (2*KEYBOARD_MARGIN);
418 morse_mode = false;
419 x = y = 0;
420 }
421 else
422#endif 604#endif
423 if (++page == KEYBOARD_PAGES) 605 if (++page == pages)
424 {
425 page = 0; 606 page = 0;
426#ifdef HAVE_MORSE_INPUT 607 k = (page*lines + y)*max_chars + x;
427 main_y = LCD_HEIGHT - font_h; 608 kbd_spellchar(kbd_buf[k]);
428 morse_mode = true;
429 /* FIXME: We should talk something like Morse mode.. */
430 break ;
431#endif
432 }
433 line = kbdpages[page];
434 c = utf8seek(line[y], x);
435 kbd_spellchar(line[y][c]);
436 break; 609 break;
437#endif 610#endif
438 611
612#ifdef KBD_MORSE_INPUT
613 case KBD_MORSE_INPUT:
614 morse_mode = !morse_mode;
615 x = y = page = 0;
616 if (morse_mode) {
617 old_main_y = main_y;
618 main_y = LCD_HEIGHT - font_h;
619 } else
620 main_y = old_main_y;
621 /* FIXME: We should talk something like Morse mode.. */
622 break;
623#endif
439 case KBD_RIGHT: 624 case KBD_RIGHT:
440 case KBD_RIGHT | BUTTON_REPEAT: 625 case KBD_RIGHT | BUTTON_REPEAT:
441#ifdef HAVE_MORSE_INPUT 626#ifdef KBD_MORSE_INPUT
442 if (morse_mode) 627 if (morse_mode)
443 break; 628 break;
444#endif 629#endif
445#ifdef KBD_MODES 630#ifdef KBD_MODES
446 if (line_edit) /* right doubles as cursor_right in line_edit */ 631 if (line_edit) /* right doubles as cursor_right in line_edit */
447 { 632 {
633 if (hangul) {
634 hangul = false;
635 hlead=hvowel=htail=0;
636 break;
637 }
448 if (editpos < len_utf8) 638 if (editpos < len_utf8)
449 { 639 {
450 editpos++; 640 editpos++;
@@ -455,32 +645,33 @@ int kbd_input(char* text, int buflen)
455 else 645 else
456#endif 646#endif
457 { 647 {
458 if (x < (int)utf8length(line[y]) - 1) 648 if (++x == max_chars) {
459 x++;
460 else
461 {
462 x = 0; 649 x = 0;
463#if !defined(KBD_PAGE_FLIP) && KEYBOARD_PAGES > 1 650#if !defined(KBD_PAGE_FLIP)
464 /* no dedicated flip key - flip page on wrap */ 651 /* no dedicated flip key - flip page on wrap */
465 if (++page == KEYBOARD_PAGES) 652 if (++page == pages)
466 page = 0; 653 page = 0;
467 line = kbdpages[page];
468#endif 654#endif
469 } 655 }
470 c = utf8seek(line[y], x); 656 k = (page*lines + y)*max_chars + x;
471 kbd_spellchar(line[y][c]); 657 kbd_spellchar(kbd_buf[k]);
472 } 658 }
473 break; 659 break;
474 660
475 case KBD_LEFT: 661 case KBD_LEFT:
476 case KBD_LEFT | BUTTON_REPEAT: 662 case KBD_LEFT | BUTTON_REPEAT:
477#ifdef HAVE_MORSE_INPUT 663#ifdef KBD_MORSE_INPUT
478 if (morse_mode) 664 if (morse_mode)
479 break; 665 break;
480#endif 666#endif
481#ifdef KBD_MODES 667#ifdef KBD_MODES
482 if (line_edit) /* left doubles as cursor_left in line_edit */ 668 if (line_edit) /* left doubles as cursor_left in line_edit */
483 { 669 {
670 if (hangul) {
671 hangul = false;
672 hlead=hvowel=htail=0;
673 break;
674 }
484 if (editpos) 675 if (editpos)
485 { 676 {
486 editpos--; 677 editpos--;
@@ -490,27 +681,26 @@ int kbd_input(char* text, int buflen)
490 } 681 }
491 else 682 else
492#endif 683#endif
493 { 684 {
494 if (x) 685 if (x)
495 x--; 686 x--;
496 else 687 else
497 { 688 {
498#if !defined(KBD_PAGE_FLIP) && KEYBOARD_PAGES > 1 689#if !defined(KBD_PAGE_FLIP)
499 /* no dedicated flip key - flip page on wrap */ 690 /* no dedicated flip key - flip page on wrap */
500 if (--page < 0) 691 if (--page < 0)
501 page = (KEYBOARD_PAGES-1); 692 page = (pages-1);
502 line = kbdpages[page];
503#endif 693#endif
504 x = utf8length(line[y]) - 1; 694 x = max_chars - 1;
505 } 695 }
506 c = utf8seek(line[y], x); 696 k = (page*lines + y)*max_chars + x;
507 kbd_spellchar(line[y][c]); 697 kbd_spellchar(kbd_buf[k]);
508 } 698 }
509 break; 699 break;
510 700
511 case KBD_DOWN: 701 case KBD_DOWN:
512 case KBD_DOWN | BUTTON_REPEAT: 702 case KBD_DOWN | BUTTON_REPEAT:
513#ifdef HAVE_MORSE_INPUT 703#ifdef KBD_MORSE_INPUT
514 if (morse_mode) 704 if (morse_mode)
515 break; 705 break;
516#endif 706#endif
@@ -523,7 +713,7 @@ int kbd_input(char* text, int buflen)
523 else 713 else
524 { 714 {
525#endif 715#endif
526 if (y < KEYBOARD_LINES - 1) 716 if (y < lines - 1)
527 y++; 717 y++;
528 else 718 else
529#ifndef KBD_MODES 719#ifndef KBD_MODES
@@ -533,20 +723,22 @@ int kbd_input(char* text, int buflen)
533 } 723 }
534 if (!line_edit) 724 if (!line_edit)
535#endif 725#endif
536 c = utf8seek(line[y], x); 726 {
537 kbd_spellchar(line[y][c]); 727 k = (page*lines + y)*max_chars + x;
728 kbd_spellchar(kbd_buf[k]);
729 }
538 break; 730 break;
539 731
540 case KBD_UP: 732 case KBD_UP:
541 case KBD_UP | BUTTON_REPEAT: 733 case KBD_UP | BUTTON_REPEAT:
542#ifdef HAVE_MORSE_INPUT 734#ifdef KBD_MORSE_INPUT
543 if (morse_mode) 735 if (morse_mode)
544 break; 736 break;
545#endif 737#endif
546#ifdef KBD_MODES 738#ifdef KBD_MODES
547 if (line_edit) 739 if (line_edit)
548 { 740 {
549 y = KEYBOARD_LINES - 1; 741 y = lines - 1;
550 line_edit = false; 742 line_edit = false;
551 } 743 }
552 else 744 else
@@ -556,14 +748,16 @@ int kbd_input(char* text, int buflen)
556 y--; 748 y--;
557 else 749 else
558#ifndef KBD_MODES 750#ifndef KBD_MODES
559 y = KEYBOARD_LINES - 1; 751 y = lines - 1;
560#else 752#else
561 line_edit = true; 753 line_edit = true;
562 } 754 }
563 if (!line_edit) 755 if (!line_edit)
564#endif 756#endif
565 c = utf8seek(line[y], x); 757 {
566 kbd_spellchar(line[y][c]); 758 k = (page*lines + y)*max_chars + x;
759 kbd_spellchar(kbd_buf[k]);
760 }
567 break; 761 break;
568 762
569 case KBD_DONE: 763 case KBD_DONE:
@@ -575,7 +769,7 @@ int kbd_input(char* text, int buflen)
575 done = true; 769 done = true;
576 break; 770 break;
577 771
578#ifdef HAVE_MORSE_INPUT 772#ifdef KBD_MORSE_INPUT
579 case KBD_SELECT | BUTTON_REL: 773 case KBD_SELECT | BUTTON_REL:
580 if (morse_mode && morse_reading) 774 if (morse_mode && morse_reading)
581 { 775 {
@@ -588,7 +782,7 @@ int kbd_input(char* text, int buflen)
588#endif 782#endif
589 783
590 case KBD_SELECT: 784 case KBD_SELECT:
591#ifdef HAVE_MORSE_INPUT 785#ifdef KBD_MORSE_INPUT
592 if (morse_mode) 786 if (morse_mode)
593 { 787 {
594 morse_tick = current_tick; 788 morse_tick = current_tick;
@@ -607,44 +801,94 @@ int kbd_input(char* text, int buflen)
607 break; 801 break;
608#endif 802#endif
609#ifdef KBD_MODES 803#ifdef KBD_MODES
610 if (line_edit) /* select doubles as backspace in line_edit */ 804 if (line_edit) { /* select doubles as backspace in line_edit */
611 { 805 if (hangul) {
612 if (editpos > 0) 806 if (htail != 0)
613 { 807 htail = 0;
614 utf8 = text + utf8seek(text, editpos); 808 else if (hvowel != 0)
615 i = 0; 809 hvowel = 0;
616 do { 810 else {
617 i++; 811 hlead = 0;
618 utf8--; 812 hangul = false;
619 } while ((*utf8 & MASK) == COMP);
620 while (utf8[i]) {
621 *utf8 = utf8[i];
622 utf8++;
623 } 813 }
624 *utf8 = 0; 814 }
625 editpos--; 815 kbd_delchar(text, &editpos);
816 if (hangul) {
817 if (hvowel != 0)
818 ch = hangul_join(hlead, hvowel, htail);
819 else
820 ch = hlead;
821 kbd_inschar(text, buflen, &editpos, ch);
626 } 822 }
627 } 823 }
628 else 824 else
629#endif 825#endif
630 { 826 {
631 const unsigned char *inschar = line[y] + utf8seek(line[y], x); 827 /* find input char */
632 j = 0; 828 k = (page*lines + y)*max_chars + x;
633 do { 829 if (k < nchars)
634 j++; 830 ch = kbd_buf[k];
635 } while ((inschar[j] & MASK) == COMP); 831 else
636 if (len + j < buflen) 832 ch = ' ';
637 { 833
638 int k = len_utf8; 834 /* check for hangul input */
639 for (i = len+j; k >= editpos; i--) { 835 if (ch >= 0x3131 && ch <= 0x3163) {
640 text[i] = text[i-j]; 836 if (hangul) {
641 if ((text[i] & MASK) != COMP) 837 if ((hvowel == 0) && (jamo_table[ch-0x3131][1] != 0)) {
642 k--; 838 hvowel = ch;
839 ch = hangul_join(hlead, hvowel, htail);
840 kbd_delchar(text, &editpos);
841 }
842 else if ((htail == 0) && (hvowel != 0) && (jamo_table[ch-0x3131][2] != 0)) {
843 htail = ch;
844 /* combine into hangul */
845 ch = hangul_join(hlead, hvowel, htail);
846 kbd_delchar(text, &editpos);
847 }
848 else { /* invalid following char or hangul complete */
849 /* check whether tail is actually lead of next char */
850 if (htail != 0 && (jamo_table[htail-0x3131][0] != 0)
851 && (jamo_table[ch-0x3131][1] != 0)) {
852 tmp = hangul_join(hlead, hvowel, 0);
853 kbd_delchar(text, &editpos);
854 kbd_inschar(text, buflen, &editpos, tmp);
855 hlead = htail;
856 hvowel = ch;
857 htail = 0;
858 ch = hangul_join(hlead, hvowel, htail);
859 }
860 else if (hlead != 0 && hvowel != 0) {
861 /* finish previous hangul */
862 tmp = hangul_join(hlead, hvowel, htail);
863 kbd_delchar(text, &editpos);
864 kbd_inschar(text, buflen, &editpos, tmp);
865 hlead=hvowel=htail=0;
866 /* start of new hangul? */
867 if (jamo_table[ch-0x3131][0] != 0) {
868 hlead = ch;
869 }
870 else
871 hangul = false;
872 }
873 }
643 } 874 }
644 while (j--) 875 else if (jamo_table[ch-0x3131][0] != 0) {
645 text[i--] = inschar[j]; 876 hlead = ch;
646 editpos++; 877 hangul = true;
878 }
879 }
880 else if (hangul) {
881 /* finish previous hangul */
882 if (hlead != 0 && hvowel != 0) {
883 tmp = hangul_join(hlead, hvowel, htail);
884 kbd_delchar(text, &editpos);
885 kbd_inschar(text, buflen, &editpos, tmp);
886 }
887 hangul = false;
888 hlead=hvowel=htail=0;
647 } 889 }
890 /* insert char */
891 kbd_inschar(text, buflen, &editpos, ch);
648 } 892 }
649 if (global_settings.talk_menu) /* voice UI? */ 893 if (global_settings.talk_menu) /* voice UI? */
650 talk_spell(text, false); /* speak revised text */ 894 talk_spell(text, false); /* speak revised text */
@@ -653,20 +897,23 @@ int kbd_input(char* text, int buflen)
653#ifndef KBD_MODES 897#ifndef KBD_MODES
654 case KBD_BACKSPACE: 898 case KBD_BACKSPACE:
655 case KBD_BACKSPACE | BUTTON_REPEAT: 899 case KBD_BACKSPACE | BUTTON_REPEAT:
656 if (editpos > 0) 900 if (hangul) {
657 { 901 if (htail != 0)
658 utf8 = text + utf8seek(text, editpos); 902 htail = 0;
659 i = 0; 903 else if (hvowel != 0)
660 do { 904 hvowel = 0;
661 i++; 905 else {
662 utf8--; 906 hlead = 0;
663 } while ((*utf8 & MASK) == COMP); 907 hangul = false;
664 while (utf8[i]) {
665 *utf8 = utf8[i];
666 utf8++;
667 } 908 }
668 *utf8 = 0; 909 }
669 editpos--; 910 kbd_delchar(text, &editpos);
911 if (hangul) {
912 if (hvowel != 0)
913 ch = hangul_join(hlead, hvowel, htail);
914 else
915 ch = hlead;
916 kbd_inschar(text, buflen, &editpos, ch);
670 } 917 }
671 if (global_settings.talk_menu) /* voice UI? */ 918 if (global_settings.talk_menu) /* voice UI? */
672 talk_spell(text, false); /* speak revised text */ 919 talk_spell(text, false); /* speak revised text */
@@ -674,6 +921,11 @@ int kbd_input(char* text, int buflen)
674 921
675 case KBD_CURSOR_RIGHT: 922 case KBD_CURSOR_RIGHT:
676 case KBD_CURSOR_RIGHT | BUTTON_REPEAT: 923 case KBD_CURSOR_RIGHT | BUTTON_REPEAT:
924 if (hangul) {
925 hangul = false;
926 hlead=hvowel=htail=0;
927 break;
928 }
677 if (editpos < len_utf8) 929 if (editpos < len_utf8)
678 { 930 {
679 editpos++; 931 editpos++;
@@ -684,6 +936,11 @@ int kbd_input(char* text, int buflen)
684 936
685 case KBD_CURSOR_LEFT: 937 case KBD_CURSOR_LEFT:
686 case KBD_CURSOR_LEFT | BUTTON_REPEAT: 938 case KBD_CURSOR_LEFT | BUTTON_REPEAT:
939 if (hangul) {
940 hangul = false;
941 hlead=hvowel=htail=0;
942 break;
943 }
687 if (editpos) 944 if (editpos)
688 { 945 {
689 editpos--; 946 editpos--;
@@ -696,7 +953,7 @@ int kbd_input(char* text, int buflen)
696 case BUTTON_NONE: 953 case BUTTON_NONE:
697 gui_syncstatusbar_draw(&statusbars, false); 954 gui_syncstatusbar_draw(&statusbars, false);
698 redraw = false; 955 redraw = false;
699#ifdef HAVE_MORSE_INPUT 956#ifdef KBD_MORSE_INPUT
700 if (morse_reading) 957 if (morse_reading)
701 { 958 {
702 logf("Morse: 0x%02x", morse_code); 959 logf("Morse: 0x%02x", morse_code);
@@ -713,15 +970,15 @@ int kbd_input(char* text, int buflen)
713 logf("Morse code not found"); 970 logf("Morse code not found");
714 break ; 971 break ;
715 } 972 }
716 973
717 if (len + 1 < buflen) 974 /* finish hangul char if necessary */
718 { 975 if (hangul) {
719 for (i = len ; i > editpos; i--) 976 hangul = false;
720 text[i] = text[i-1]; 977 hlead=hvowel=htail=0;
721 text[len+1] = 0;
722 text[editpos] = morse_alphabets[j];
723 editpos++;
724 } 978 }
979
980 kbd_inschar(text, buflen, &editpos, morse_alphabets[j]);
981
725 if (global_settings.talk_menu) /* voice UI? */ 982 if (global_settings.talk_menu) /* voice UI? */
726 talk_spell(text, false); /* speak revised text */ 983 talk_spell(text, false); /* speak revised text */
727 redraw = true; 984 redraw = true;
diff --git a/apps/settings.c b/apps/settings.c
index 6ea7c34a31..4068f78015 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -916,6 +916,11 @@ int settings_save( void )
916 MAX_FILENAME); 916 MAX_FILENAME);
917 i+= MAX_FILENAME; 917 i+= MAX_FILENAME;
918#endif 918#endif
919#ifdef HAVE_LCD_BITMAP
920 strncpy((char *)&config_block[i], (char *)global_settings.kbd_file,
921 MAX_FILENAME);
922 i+= MAX_FILENAME;
923#endif
919 924
920 if(save_config_buffer()) 925 if(save_config_buffer())
921 { 926 {
@@ -1108,6 +1113,15 @@ void settings_apply(void)
1108 else 1113 else
1109 font_reset(); 1114 font_reset();
1110 1115
1116 if ( global_settings.kbd_file[0] &&
1117 global_settings.kbd_file[0] != 0xff ) {
1118 snprintf(buf, sizeof buf, ROCKBOX_DIR "/%s.kbd",
1119 global_settings.kbd_file);
1120 load_kbd(buf);
1121 }
1122 else
1123 load_kbd(NULL);
1124
1111 lcd_scroll_step(global_settings.scroll_step); 1125 lcd_scroll_step(global_settings.scroll_step);
1112 gui_list_screen_scroll_step(global_settings.screen_scroll_step); 1126 gui_list_screen_scroll_step(global_settings.screen_scroll_step);
1113 gui_list_screen_scroll_out_of_view(global_settings.offset_out_of_view); 1127 gui_list_screen_scroll_out_of_view(global_settings.offset_out_of_view);
@@ -1253,6 +1267,11 @@ void settings_load(int which)
1253 MAX_FILENAME); 1267 MAX_FILENAME);
1254 i+= MAX_FILENAME; 1268 i+= MAX_FILENAME;
1255#endif 1269#endif
1270#ifdef HAVE_LCD_BITMAP
1271 strncpy((char *)global_settings.kbd_file, (char *)&config_block[i],
1272 MAX_FILENAME);
1273 i+= MAX_FILENAME;
1274#endif
1256 } 1275 }
1257} 1276}
1258 1277
@@ -1425,6 +1444,12 @@ bool settings_load_config(const char* file)
1425 set_file(value, (char *)global_settings.backdrop_file, MAX_FILENAME); 1444 set_file(value, (char *)global_settings.backdrop_file, MAX_FILENAME);
1426 } 1445 }
1427#endif 1446#endif
1447#ifdef HAVE_LCD_BITMAP
1448 else if (!strcasecmp(name, "keyboard")) {
1449 if (!load_kbd(value))
1450 set_file(value, (char *)global_settings.kbd_file, MAX_FILENAME);
1451 }
1452#endif
1428 1453
1429 1454
1430 /* check for scalar values, using the two tables */ 1455 /* check for scalar values, using the two tables */
@@ -1583,6 +1608,12 @@ bool settings_save_config(void)
1583 global_settings.backdrop_file); 1608 global_settings.backdrop_file);
1584#endif 1609#endif
1585 1610
1611#ifdef HAVE_LCD_BITMAP
1612 if (global_settings.kbd_file[0] != 0)
1613 fdprintf(fd, "keyboard: %s/%s.kbd\r\n", ROCKBOX_DIR,
1614 global_settings.kbd_file);
1615#endif
1616
1586 /* here's the action: write values to file, specified via table */ 1617 /* here's the action: write values to file, specified via table */
1587 save_cfg_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), fd); 1618 save_cfg_table(rtc_bits, sizeof(rtc_bits)/sizeof(rtc_bits[0]), fd);
1588 save_cfg_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), fd); 1619 save_cfg_table(hd_bits, sizeof(hd_bits)/sizeof(hd_bits[0]), fd);
@@ -1666,6 +1697,9 @@ void settings_reset(void) {
1666 global_settings.fg_color = LCD_DEFAULT_FG; 1697 global_settings.fg_color = LCD_DEFAULT_FG;
1667 global_settings.bg_color = LCD_DEFAULT_BG; 1698 global_settings.bg_color = LCD_DEFAULT_BG;
1668#endif 1699#endif
1700#ifdef HAVE_LCD_BITMAP
1701 global_settings.kbd_file[0] = '\0';
1702#endif
1669 1703
1670} 1704}
1671 1705
diff --git a/apps/settings.h b/apps/settings.h
index 3616434642..498c880319 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -481,6 +481,10 @@ struct user_settings
481 bool remote_bl_filter_first_keypress; /* filter first remote keypress when remote dark? */ 481 bool remote_bl_filter_first_keypress; /* filter first remote keypress when remote dark? */
482#endif 482#endif
483#endif 483#endif
484
485#ifdef HAVE_LCD_BITMAP
486 unsigned char kbd_file[MAX_FILENAME+1]; /* last keyboard */
487#endif
484}; 488};
485 489
486enum optiontype { INT, BOOL }; 490enum optiontype { INT, BOOL };
diff --git a/apps/tree.c b/apps/tree.c
index 0df5baefd3..61f6971018 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -110,6 +110,7 @@ const struct filetype filetypes[] = {
110 { "rock",TREE_ATTR_ROCK,Icon_Plugin, VOICE_EXT_ROCK }, 110 { "rock",TREE_ATTR_ROCK,Icon_Plugin, VOICE_EXT_ROCK },
111#ifdef HAVE_LCD_BITMAP 111#ifdef HAVE_LCD_BITMAP
112 { "fnt", TREE_ATTR_FONT,Icon_Font, VOICE_EXT_FONT }, 112 { "fnt", TREE_ATTR_FONT,Icon_Font, VOICE_EXT_FONT },
113 { "kbd", TREE_ATTR_KBD, Icon_Keyboard, VOICE_EXT_KBD },
113#endif 114#endif
114 { "bmark",TREE_ATTR_BMARK, Icon_Bookmark, VOICE_EXT_BMARK }, 115 { "bmark",TREE_ATTR_BMARK, Icon_Bookmark, VOICE_EXT_BMARK },
115#ifdef BOOTFILE_EXT 116#ifdef BOOTFILE_EXT
diff --git a/apps/tree.h b/apps/tree.h
index 85dd7f6e1c..6f91f7fcd1 100644
--- a/apps/tree.h
+++ b/apps/tree.h
@@ -241,6 +241,7 @@ struct tree_context {
241#define TREE_ATTR_MOD 0x0900 /* firmware file */ 241#define TREE_ATTR_MOD 0x0900 /* firmware file */
242#define TREE_ATTR_RWPS 0x1000 /* remote-wps config file */ 242#define TREE_ATTR_RWPS 0x1000 /* remote-wps config file */
243#define TREE_ATTR_BMP 0x1100 /* backdrop bmp file */ 243#define TREE_ATTR_BMP 0x1100 /* backdrop bmp file */
244#define TREE_ATTR_KBD 0x1200 /* keyboard file */
244#define TREE_ATTR_MASK 0xFF00 /* which bits tree.c uses for file types */ 245#define TREE_ATTR_MASK 0xFF00 /* which bits tree.c uses for file types */
245 246
246void tree_get_filetypes(const struct filetype**, int*); 247void tree_get_filetypes(const struct filetype**, int*);
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 3dbe1e12b9..d145176145 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -63,6 +63,7 @@ drivers/lcd-player.c
63#ifdef HAVE_LCD_BITMAP 63#ifdef HAVE_LCD_BITMAP
64arabjoin.c 64arabjoin.c
65bidi.c 65bidi.c
66hangul.c
66#if LCD_DEPTH == 1 67#if LCD_DEPTH == 1
67drivers/lcd-recorder.c 68drivers/lcd-recorder.c
68#elif LCD_DEPTH == 2 69#elif LCD_DEPTH == 2
diff --git a/firmware/export/hangul.h b/firmware/export/hangul.h
new file mode 100644
index 0000000000..d5f8b0636c
--- /dev/null
+++ b/firmware/export/hangul.h
@@ -0,0 +1,23 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 *
10 * Copyright (C) 2006 by Frank Dischner
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20extern const char jamo_table[51][3];
21
22unsigned short hangul_join(unsigned short lead, unsigned short vowel,
23 unsigned short tail);
diff --git a/firmware/hangul.c b/firmware/hangul.c
new file mode 100644
index 0000000000..27123ccb64
--- /dev/null
+++ b/firmware/hangul.c
@@ -0,0 +1,101 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 *
9 *
10 * Copyright (C) 2006 by Frank Dischner
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "hangul.h"
20
21const char jamo_table[51][3] = {
22 { 1, 0, 1},
23 { 2, 0, 2},
24 { 0, 0, 3},
25 { 3, 0, 4},
26 { 0, 0, 5},
27 { 0, 0, 6},
28 { 4, 0, 7},
29 { 5, 0, 0},
30 { 6, 0, 8},
31 { 0, 0, 9},
32 { 0, 0, 10},
33 { 0, 0, 11},
34 { 0, 0, 12},
35 { 0, 0, 13},
36 { 0, 0, 14},
37 { 0, 0, 15},
38 { 7, 0, 16},
39 { 8, 0, 17},
40 { 9, 0, 0},
41 { 0, 0, 18},
42 {10, 0, 19},
43 {11, 0, 20},
44 {12, 0, 21},
45 {13, 0, 22},
46 {14, 0, 0},
47 {15, 0, 23},
48 {16, 0, 24},
49 {17, 0, 25},
50 {18, 0, 26},
51 {19, 0, 27},
52 { 0, 1, 0},
53 { 0, 2, 0},
54 { 0, 3, 0},
55 { 0, 4, 0},
56 { 0, 5, 0},
57 { 0, 6, 0},
58 { 0, 7, 0},
59 { 0, 8, 0},
60 { 0, 9, 0},
61 { 0, 10, 0},
62 { 0, 11, 0},
63 { 0, 12, 0},
64 { 0, 13, 0},
65 { 0, 14, 0},
66 { 0, 15, 0},
67 { 0, 16, 0},
68 { 0, 17, 0},
69 { 0, 18, 0},
70 { 0, 19, 0},
71 { 0, 20, 0},
72 { 0, 21, 0},
73};
74
75/* takes three jamo chars and joins them into one hangul */
76unsigned short hangul_join(unsigned short lead, unsigned short vowel,
77 unsigned short tail)
78{
79 unsigned short ch = 0xfffd;
80
81 if (lead < 0x3131 || lead > 0x3163)
82 return ch;
83 lead = jamo_table[lead-0x3131][0];
84
85 if (vowel < 0x3131 || vowel > 0x3163)
86 return ch;
87 vowel = jamo_table[vowel-0x3131][1];
88
89 if (tail) {
90 if (tail < 0x3131 || tail > 0x3163)
91 return ch;
92 tail = jamo_table[tail-0x3131][2];
93 if (!tail)
94 return ch;
95 }
96
97 if (lead && vowel)
98 ch = tail + (vowel - 1)*28 + (lead - 1)*588 + 44032;
99
100 return ch;
101}