diff options
author | Frank Dischner <phaedrus961@rockbox.org> | 2006-03-29 16:21:42 +0000 |
---|---|---|
committer | Frank Dischner <phaedrus961@rockbox.org> | 2006-03-29 16:21:42 +0000 |
commit | 75c3d0b9f10ea30b827052b7a6f894734e705c4f (patch) | |
tree | ec6bfd1a7f7812bf1d7523b597bada006646cb82 | |
parent | 0fec4711d5ba5fff1b321568fb45651e11d79b08 (diff) | |
download | rockbox-75c3d0b9f10ea30b827052b7a6f894734e705c4f.tar.gz rockbox-75c3d0b9f10ea30b827052b7a6f894734e705c4f.zip |
Add support for loadable vkeyboard layouts
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9347 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/filetree.c | 9 | ||||
-rw-r--r-- | apps/keyboard.h | 4 | ||||
-rw-r--r-- | apps/lang/english.lang | 11 | ||||
-rw-r--r-- | apps/recorder/icons.c | 1 | ||||
-rw-r--r-- | apps/recorder/icons.h | 1 | ||||
-rw-r--r-- | apps/recorder/keyboard.c | 639 | ||||
-rw-r--r-- | apps/settings.c | 34 | ||||
-rw-r--r-- | apps/settings.h | 4 | ||||
-rw-r--r-- | apps/tree.c | 1 | ||||
-rw-r--r-- | apps/tree.h | 1 | ||||
-rw-r--r-- | firmware/SOURCES | 1 | ||||
-rw-r--r-- | firmware/export/hangul.h | 23 | ||||
-rw-r--r-- | firmware/hangul.c | 101 |
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 |
46 | static int boot_size = 0; | 49 | static 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 | ||
22 | int kbd_input(char* buffer, int buflen); | 22 | int kbd_input(char* buffer, int buflen); |
23 | 23 | ||
24 | #ifdef HAVE_LCD_BITMAP | ||
25 | int 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" | |||
3887 | voice: "Pre-cut" | 3887 | voice: "Pre-cut" |
3888 | new: | 3888 | new: |
3889 | 3889 | ||
3890 | id: LANG_KEYBOARD_LOADED | ||
3891 | desc: shown when a keyboard has been loaded from the dir browser | ||
3892 | eng: "New Keyboard" | ||
3893 | voice: "" | ||
3894 | new: | ||
3895 | |||
3896 | id: VOICE_EXT_KBD | ||
3897 | desc: spoken only, for file extension | ||
3898 | eng: "" | ||
3899 | voice: "keyboard" | ||
3900 | new: | ||
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 | ||
54 | const unsigned char bitmap_icons_7x8[][7] = | 55 | const 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) |
176 | static const char * const kbdpages[KEYBOARD_PAGES][KEYBOARD_LINES] = { | 185 | static 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 |
188 | static const char * const kbdpages[KEYBOARD_PAGES][KEYBOARD_LINES] = { | 195 | static 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 | 212 | static unsigned short kbd_buf[KBD_BUF_SIZE]; |
213 | static bool kbd_loaded = false; | ||
214 | static 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. */ |
209 | static const char *morse_alphabets = | 218 | static const char *morse_alphabets = |
210 | "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ "; | 219 | "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ "; |
@@ -217,37 +226,139 @@ static const unsigned char morse_codes[] = { | |||
217 | static bool morse_mode = false; | 226 | static bool morse_mode = false; |
218 | #endif | 227 | #endif |
219 | 228 | ||
229 | /* Loads a custom keyboard into memory | ||
230 | call with NULL to reset keyboard */ | ||
231 | int 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 */ |
221 | static void kbd_spellchar(char c) | 281 | static 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 | ||
292 | void 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 | |||
317 | void 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 | |||
232 | int kbd_input(char* text, int buflen) | 340 | int 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 | ||
486 | enum optiontype { INT, BOOL }; | 490 | enum 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 | ||
246 | void tree_get_filetypes(const struct filetype**, int*); | 247 | void 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 |
64 | arabjoin.c | 64 | arabjoin.c |
65 | bidi.c | 65 | bidi.c |
66 | hangul.c | ||
66 | #if LCD_DEPTH == 1 | 67 | #if LCD_DEPTH == 1 |
67 | drivers/lcd-recorder.c | 68 | drivers/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 | |||
20 | extern const char jamo_table[51][3]; | ||
21 | |||
22 | unsigned 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 | |||
21 | const 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 */ | ||
76 | unsigned 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 | } | ||