Fix yellows.
[kugel-rb/myfork.git] / apps / recorder / keyboard.c
blob0fa1d325032ba25290c8c7627e3099c2aa921b50
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Björn Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "kernel.h"
22 #include "system.h"
23 #include "version.h"
24 #include <string.h>
25 #include "font.h"
26 #include "screens.h"
27 #include "talk.h"
28 #include "settings.h"
29 #include "misc.h"
30 #include "rbunicode.h"
31 #include "buttonbar.h"
32 #include "logf.h"
33 #include "hangul.h"
34 #include "action.h"
35 #include "icon.h"
36 #include "pcmbuf.h"
37 #include "lang.h"
38 #include "keyboard.h"
39 #include "viewport.h"
40 #include "file.h"
41 #include "splash.h"
43 #ifndef O_BINARY
44 #define O_BINARY 0
45 #endif
48 #define DEFAULT_MARGIN 6
49 #define KBD_BUF_SIZE 500
51 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
52 (CONFIG_KEYPAD == IRIVER_H300_PAD)
53 #define KBD_CURSOR_KEYS /* certain key combos move the cursor even if not
54 in line edit mode */
55 #define KBD_MODES /* I-Rivers can use picker, line edit and cursor keys */
56 #define KBD_MORSE_INPUT /* I-Rivers have a Morse input mode */
58 #elif CONFIG_KEYPAD == ONDIO_PAD /* restricted Ondio keypad */
59 #define KBD_MODES /* Ondio uses 2 modes, picker and line edit */
61 #elif (CONFIG_KEYPAD == IPOD_1G2G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) \
62 || (CONFIG_KEYPAD == IPOD_4G_PAD)
63 #define KBD_MODES /* iPod uses 2 modes, picker and line edit */
64 #define KBD_MORSE_INPUT
66 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
67 #define KBD_MODES /* iFP7xx uses 2 modes, picker and line edit */
69 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) || (CONFIG_KEYPAD == IAUDIO_M3_PAD)
70 #define KBD_MODES /* iAudios use 2 modes, picker and line edit */
72 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
73 #define KBD_MODES /* iriver H10 uses 2 modes, picker and line edit */
74 #define KBD_MORSE_INPUT
76 #elif CONFIG_KEYPAD == GIGABEAT_PAD
77 #define KBD_CURSOR_KEYS
78 #define KBD_MODES
79 #define KBD_MORSE_INPUT
81 #elif CONFIG_KEYPAD == SANSA_E200_PAD \
82 || CONFIG_KEYPAD == SANSA_FUZE_PAD
83 #define KBD_CURSOR_KEYS
84 #define KBD_MODES
86 #elif CONFIG_KEYPAD == SANSA_C200_PAD
87 #define KBD_CURSOR_KEYS
88 #define KBD_MODES
90 #elif CONFIG_KEYPAD == MROBE100_PAD
91 #define KBD_MORSE_INPUT
92 #endif
94 struct keyboard_parameters
96 const unsigned char* default_kbd;
97 int DEFAULT_LINES;
98 unsigned short kbd_buf[KBD_BUF_SIZE];
99 int nchars;
100 int font_w;
101 int font_h;
102 struct font* font;
103 int curfont;
104 int main_x;
105 int main_y;
106 int max_chars;
107 int max_chars_text;
108 int lines;
109 int pages;
110 int keyboard_margin;
111 int old_main_y;
112 int curpos;
113 int leftpos;
114 int page;
115 int x;
116 int y;
117 #ifdef KBD_MODES
118 bool line_edit;
119 #endif
120 bool hangul;
121 unsigned short hlead, hvowel, htail;
124 static struct keyboard_parameters kbd_param[NB_SCREENS];
125 static bool kbd_loaded = false;
127 #ifdef KBD_MORSE_INPUT
128 /* FIXME: We should put this to a configuration file. */
129 static const char *morse_alphabets =
130 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
131 static const unsigned char morse_codes[] = {
132 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
133 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
134 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
135 0x73,0x55,0x4c,0x61,0x5a,0x80 };
137 static bool morse_mode = false;
138 #endif
140 /* Loads a custom keyboard into memory
141 call with NULL to reset keyboard */
142 int load_kbd(unsigned char* filename)
144 int fd, l;
145 int i = 0;
146 unsigned char buf[4];
148 if (filename == NULL)
150 kbd_loaded = false;
151 return 0;
154 fd = open_utf8(filename, O_RDONLY|O_BINARY);
155 if (fd < 0)
156 return 1;
158 while (read(fd, buf, 1) == 1 && i < KBD_BUF_SIZE)
160 /* check how many bytes to read for this character */
161 static const unsigned char sizes[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
162 size_t count;
164 for (count = 0; count < ARRAYLEN(sizes); count++)
166 if (buf[0] < sizes[count])
167 break;
170 if (count >= ARRAYLEN(sizes))
171 continue; /* Invalid size. */
173 if (read(fd, &buf[1], count) != (ssize_t)count)
175 close(fd);
176 kbd_loaded = false;
177 return 1;
180 FOR_NB_SCREENS(l)
181 utf8decode(buf, &kbd_param[l].kbd_buf[i]);
183 if (kbd_param[0].kbd_buf[i] != 0xFEFF &&
184 kbd_param[0].kbd_buf[i] != '\r') /*skip BOM & carriage returns */
186 i++;
190 close(fd);
191 kbd_loaded = true;
193 FOR_NB_SCREENS(l)
194 kbd_param[l].nchars = i;
196 return 0;
199 /* helper function to spell a char if voice UI is enabled */
200 static void kbd_spellchar(unsigned short c)
202 if (global_settings.talk_menu) /* voice UI? */
204 unsigned char tmp[5];
205 /* store char to pass to talk_spell */
206 unsigned char* utf8 = utf8encode(c, tmp);
207 *utf8 = 0;
209 if(c == ' ')
210 talk_id(VOICE_BLANK, false);
211 else
212 talk_spell(tmp, false);
216 #ifdef KBD_MODES
217 static void say_edit(void)
219 if(global_settings.talk_menu)
220 talk_id(VOICE_EDIT, false);
222 #endif
224 static void kbd_inschar(unsigned char* text, int buflen,
225 int* editpos, unsigned short ch)
227 int i, j, k, len;
228 unsigned char tmp[4];
229 unsigned char* utf8;
231 len = strlen(text);
232 k = utf8length(text);
233 utf8 = utf8encode(ch, tmp);
234 j = (long)utf8 - (long)tmp;
236 if (len + j < buflen)
238 for (i = len+j; k >= *editpos; i--)
240 text[i] = text[i-j];
241 if ((text[i] & MASK) != COMP)
242 k--;
245 while (j--)
246 text[i--] = tmp[j];
248 (*editpos)++;
252 static void kbd_delchar(unsigned char* text, int* editpos)
254 int i = 0;
255 unsigned char* utf8;
257 if (*editpos > 0)
259 utf8 = text + utf8seek(text, *editpos);
263 i++;
264 utf8--;
266 while ((*utf8 & MASK) == COMP);
268 while (utf8[i])
270 *utf8 = utf8[i];
271 utf8++;
274 *utf8 = 0;
275 (*editpos)--;
279 /* Lookup k value based on state of param (pm) */
280 static int get_param_k(const struct keyboard_parameters *pm)
282 return (pm->page*pm->lines + pm->y)*pm->max_chars + pm->x;
285 int kbd_input(char* text, int buflen)
287 bool done = false;
288 #ifdef CPU_ARM
289 /* This seems to keep the sizes for ARM way down */
290 struct keyboard_parameters * volatile param = kbd_param;
291 #else
292 struct keyboard_parameters * const param = kbd_param;
293 #endif
294 int l; /* screen loop variable */
295 int text_w = 0;
296 int editpos; /* Edit position on all screens */
297 const int statusbar_size = 0;
298 unsigned short ch;
299 unsigned char *utf8;
300 bool cur_blink = true; /* Cursor on/off flag */
301 int ret = 0; /* assume success */
302 #ifdef KBD_MORSE_INPUT
303 bool morse_reading = false;
304 unsigned char morse_code = 0;
305 int morse_tick = 0;
306 char buf[2];
307 #endif
308 int oldbars = viewportmanager_set_statusbar(VP_SB_HIDE_ALL);
309 FOR_NB_SCREENS(l)
311 struct keyboard_parameters *pm = &param[l];
312 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96
313 struct screen *sc = &screens[l];
315 if (sc->getwidth() >= 160 && sc->getheight() >= 96)
317 pm->default_kbd =
318 "ABCDEFG abcdefg !?\" @#$%+'\n"
319 "HIJKLMN hijklmn 789 &_()-`\n"
320 "OPQRSTU opqrstu 456 §|{}/<\n"
321 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
322 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
323 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
324 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
325 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;";
327 pm->DEFAULT_LINES = 8;
329 else
330 #endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */
332 pm->default_kbd =
333 "ABCDEFG !?\" @#$%+'\n"
334 "HIJKLMN 789 &_()-`\n"
335 "OPQRSTU 456 §|{}/<\n"
336 "VWXYZ.,0123 ~=[]*>\n"
338 "abcdefg ¢£¤¥¦§©®¬\n"
339 "hijklmn «»°ºª¹²³¶\n"
340 "opqrstu ¯±×÷¡¿µ·¨\n"
341 "vwxyz., :;¼½¾ \n"
343 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
344 "àáâãäåæ ìíîï èéêë\n"
345 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
346 "òóôõöø çðþýÿ ùúûü";
348 pm->DEFAULT_LINES = 4;
352 char outline[256];
353 #ifdef HAVE_BUTTONBAR
354 struct gui_buttonbar buttonbar;
355 bool buttonbar_config = global_settings.buttonbar;
357 global_settings.buttonbar = true;
358 gui_buttonbar_init(&buttonbar);
360 FOR_NB_SCREENS(l)
361 gui_buttonbar_set_display(&buttonbar, &screens[l]);
362 #endif
364 FOR_NB_SCREENS(l)
366 struct keyboard_parameters *pm = &param[l];
368 if ( !kbd_loaded )
370 /* Copy default keyboard to buffer */
371 const unsigned char *p = pm->default_kbd;
372 int i = 0;
374 pm->curfont = FONT_SYSFIXED;
376 while (*p != 0)
377 p = utf8decode(p, &pm->kbd_buf[i++]);
379 pm->nchars = i;
381 else
383 pm->curfont = FONT_UI;
387 FOR_NB_SCREENS(l)
389 struct keyboard_parameters *pm = &param[l];
390 struct screen *sc = &screens[l];
391 int i, w;
393 pm->font = font_get(pm->curfont);
394 pm->font_h = pm->font->height;
396 /* check if FONT_UI fits the screen */
397 if (2*pm->font_h + 3 + statusbar_size +
398 BUTTONBAR_HEIGHT > sc->getheight())
400 pm->font = font_get(FONT_SYSFIXED);
401 pm->font_h = pm->font->height;
402 pm->curfont = FONT_SYSFIXED;
405 sc->setfont(pm->curfont);
406 pm->font_w = 0; /* reset font width */
407 /* find max width of keyboard glyphs */
408 for (i = 0; i < pm->nchars; i++)
410 w = font_get_width(pm->font, pm->kbd_buf[i]);
411 if ( w > pm->font_w )
412 pm->font_w = w;
415 /* Since we're going to be adding spaces, make sure that we check
416 * their width too */
417 w = font_get_width( pm->font, ' ' );
418 if ( w > pm->font_w )
419 pm->font_w = w;
422 FOR_NB_SCREENS(l)
424 struct keyboard_parameters *pm = &param[l];
425 struct screen *sc = &screens[l];
426 int i = 0;
428 /* Pad lines with spaces */
429 while (i < pm->nchars)
431 if (pm->kbd_buf[i] == '\n')
433 int k = sc->getwidth() / pm->font_w
434 - i % ( sc->getwidth() / pm->font_w ) - 1;
435 int j;
437 if (k == sc->getwidth() / pm->font_w - 1)
439 pm->nchars--;
441 for (j = i; j < pm->nchars; j++)
443 pm->kbd_buf[j] = pm->kbd_buf[j + 1];
446 else
448 if (pm->nchars + k - 1 >= KBD_BUF_SIZE)
449 { /* We don't want to overflow the buffer */
450 k = KBD_BUF_SIZE - pm->nchars;
453 for (j = pm->nchars + k - 1; j > i + k; j--)
455 pm->kbd_buf[j] = pm->kbd_buf[j-k];
458 pm->nchars += k;
459 k++;
461 while (k--)
463 pm->kbd_buf[i++] = ' ';
467 else
469 i++;
474 /* Find max width for text string */
475 utf8 = text;
476 FOR_NB_SCREENS(l)
478 struct keyboard_parameters *pm = &param[l];
479 struct screen *sc = &screens[l];
481 text_w = pm->font_w;
483 while (*utf8)
485 int w = font_get_width(pm->font, ch);
486 utf8 = (unsigned char*)utf8decode(utf8, &ch);
488 if (w > text_w)
489 text_w = w;
492 pm->max_chars_text = sc->getwidth() / text_w - 2;
494 /* Calculate keyboard grid size */
495 pm->max_chars = sc->getwidth() / pm->font_w;
497 if (!kbd_loaded)
499 pm->lines = pm->DEFAULT_LINES;
500 pm->keyboard_margin = DEFAULT_MARGIN;
502 else
504 pm->lines = (sc->getheight() - BUTTONBAR_HEIGHT - statusbar_size)
505 / pm->font_h - 1;
506 pm->keyboard_margin = sc->getheight() - BUTTONBAR_HEIGHT -
507 statusbar_size - (pm->lines+1)*pm->font_h;
509 if (pm->keyboard_margin < 3)
511 pm->lines--;
512 pm->keyboard_margin += pm->font_h;
515 if (pm->keyboard_margin > 6)
516 pm->keyboard_margin = 6;
519 pm->pages = (pm->nchars + (pm->lines*pm->max_chars-1))
520 / (pm->lines*pm->max_chars);
522 if (pm->pages == 1 && kbd_loaded)
523 pm->lines = (pm->nchars + pm->max_chars - 1) / pm->max_chars;
525 pm->main_y = pm->font_h*pm->lines + pm->keyboard_margin + statusbar_size;
526 pm->main_x = 0;
527 pm->keyboard_margin -= pm->keyboard_margin/2;
529 #ifdef KBD_MORSE_INPUT
530 pm->old_main_y = pm->main_y;
531 if (morse_mode)
532 pm->main_y = sc->getheight() - pm->font_h;
533 #endif
536 /* Initial edit position is after last character */
537 editpos = utf8length(text);
539 if (global_settings.talk_menu) /* voice UI? */
540 talk_spell(text, true); /* spell initial text */
543 while (!done)
545 /* These declarations are assigned to the screen on which the key
546 action occurred - pointers save a lot of space over array notation
547 when accessing the same array element countless times */
548 int button;
549 #if NB_SCREENS > 1
550 int button_screen;
551 #else
552 const int button_screen = 0;
553 #endif
554 struct keyboard_parameters *pm;
555 struct screen *sc;
557 int len_utf8 = utf8length(text);
559 FOR_NB_SCREENS(l)
560 screens[l].clear_display();
562 #ifdef KBD_MORSE_INPUT
563 if (morse_mode)
565 FOR_NB_SCREENS(l)
567 /* declare scoped pointers inside screen loops - hide the
568 declarations from previous block level */
569 const int w = 6; /* sysfixed font width */
570 struct keyboard_parameters *pm = &param[l];
571 struct screen *sc = &screens[l];
572 int i;
574 sc->setfont(FONT_SYSFIXED); /* Draw morse code screen with sysfont */
575 pm->x = 0;
576 pm->y = statusbar_size;
577 buf[1] = '\0';
579 /* Draw morse code table with code descriptions. */
580 for (i = 0; morse_alphabets[i] != '\0'; i++)
582 int morse_len;
583 int j;
585 buf[0] = morse_alphabets[i];
586 sc->putsxy(pm->x, pm->y, buf);
588 for (j = 0; (morse_codes[i] >> j) > 0x01; j++) ;
589 morse_len = j;
591 pm->x += w + 3;
592 for (j = 0; j < morse_len; j++)
594 if ((morse_codes[i] >> (morse_len-j-1)) & 0x01)
595 sc->fillrect(pm->x + j*4, pm->y + 2, 3, 4);
596 else
597 sc->fillrect(pm->x + j*4, pm->y + 3, 1, 2);
600 pm->x += w*5 - 3;
601 if (pm->x >= sc->getwidth() - w*6)
603 pm->x = 0;
604 pm->y += 8; /* sysfixed font height */
609 else
610 #endif /* KBD_MORSE_INPUT */
612 /* draw page */
613 FOR_NB_SCREENS(l)
615 struct keyboard_parameters *pm = &param[l];
616 struct screen *sc = &screens[l];
617 int i, j, k;
619 sc->setfont(pm->curfont);
621 k = pm->page*pm->max_chars*pm->lines;
623 for (i = j = 0; j < pm->lines && k < pm->nchars; k++)
625 int w;
626 utf8 = utf8encode(pm->kbd_buf[k], outline);
627 *utf8 = 0;
629 sc->getstringsize(outline, &w, NULL);
630 sc->putsxy(i*pm->font_w + (pm->font_w-w) / 2,
631 j*pm->font_h + statusbar_size, outline);
633 if (++i >= pm->max_chars)
635 i = 0;
636 j++;
642 /* separator */
643 FOR_NB_SCREENS(l)
645 struct keyboard_parameters *pm = &param[l];
646 struct screen *sc = &screens[l];
647 int i = 0, j = 0;
649 /* Clear text area one pixel above separator line so any overdraw
650 doesn't collide */
651 sc->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
652 sc->fillrect(0, pm->main_y - pm->keyboard_margin - 1,
653 sc->getwidth(), pm->font_h + 4);
654 sc->set_drawmode(DRMODE_SOLID);
656 sc->hline(0, sc->getwidth() - 1, pm->main_y - pm->keyboard_margin);
658 /* write out the text */
659 sc->setfont(pm->curfont);
661 pm->curpos = MIN(editpos, pm->max_chars_text
662 - MIN(len_utf8 - editpos, 2));
663 pm->leftpos = editpos - pm->curpos;
664 utf8 = text + utf8seek(text, pm->leftpos);
666 text_w = pm->font_w;
668 while (*utf8 && i < pm->max_chars_text)
670 outline[j++] = *utf8++;
672 if ((*utf8 & MASK) != COMP)
674 int w;
675 outline[j] = 0;
676 j=0;
677 i++;
678 sc->getstringsize(outline, &w, NULL);
679 sc->putsxy(i*text_w + (text_w-w)/2, pm->main_y, outline);
683 if (pm->leftpos > 0)
685 /* Draw nicer bitmap arrow if room, else settle for "<". */
686 if (text_w >= 6 && pm->font_h >= 8)
688 screen_put_iconxy(sc, (text_w - 6) / 2,
689 pm->main_y + (pm->font_h - 8) / 2 ,
690 Icon_Reverse_Cursor);
692 else
694 int w;
695 sc->getstringsize("<", &w, NULL);
696 sc->putsxy(text_w - w, pm->main_y, "<");
700 if (len_utf8 - pm->leftpos > pm->max_chars_text)
702 /* Draw nicer bitmap arrow if room, else settle for ">". */
703 if (text_w >= 6 && pm->font_h >= 8)
705 screen_put_iconxy(sc, sc->getwidth() - text_w +
706 (text_w - 6) / 2,
707 pm->main_y + (pm->font_h - 8) / 2,
708 Icon_Cursor);
710 else
712 sc->putsxy(sc->getwidth() - text_w, pm->main_y, ">");
716 /* cursor */
717 i = (pm->curpos + 1) * text_w;
719 if (cur_blink)
720 sc->vline(i, pm->main_y, pm->main_y + pm->font_h - 1);
722 if (pm->hangul) /* draw underbar */
723 sc->hline(pm->curpos*text_w, (pm->curpos+1)*text_w,
724 pm->main_y + pm->font_h - 1);
727 cur_blink = !cur_blink;
729 #ifdef HAVE_BUTTONBAR
730 /* draw the button bar */
731 gui_buttonbar_set(&buttonbar, "Shift", "OK", "Del");
732 gui_buttonbar_draw(&buttonbar);
733 #endif
735 FOR_NB_SCREENS(l)
737 struct keyboard_parameters *pm = &param[l];
738 struct screen *sc = &screens[l];
740 sc->set_drawmode(DRMODE_COMPLEMENT);
741 #ifdef KBD_MODES
742 if (pm->line_edit)
743 sc->fillrect(0, pm->main_y - pm->keyboard_margin + 2,
744 sc->getwidth(), pm->font_h + 2);
745 else /* highlight the key that has focus */
746 #endif
747 sc->fillrect(pm->font_w*pm->x,
748 statusbar_size + pm->font_h*pm->y,
749 pm->font_w, pm->font_h);
750 sc->set_drawmode(DRMODE_SOLID);
753 FOR_NB_SCREENS(l)
754 screens[l].update();
756 button = get_action(CONTEXT_KEYBOARD, HZ/2);
757 #if NB_SCREENS > 1
758 button_screen = (get_action_statuscode(NULL) & ACTION_REMOTE) ? 1 : 0;
759 #endif
760 pm = &param[button_screen];
761 sc = &screens[button_screen];
763 #if defined KBD_MORSE_INPUT && !defined KBD_MODES
764 if (morse_mode)
766 /* Remap some buttons for morse mode. */
767 if (button == ACTION_KBD_LEFT)
768 button = ACTION_KBD_CURSOR_LEFT;
769 if (button == ACTION_KBD_RIGHT)
770 button = ACTION_KBD_CURSOR_RIGHT;
772 #endif
774 switch ( button )
776 case ACTION_KBD_ABORT:
777 FOR_NB_SCREENS(l)
778 screens[l].setfont(FONT_UI);
779 ret = -1; done = true;
780 break;
782 case ACTION_KBD_PAGE_FLIP:
784 int k;
785 #ifdef KBD_MORSE_INPUT
786 if (morse_mode)
787 break;
788 #endif
789 if (++pm->page >= pm->pages)
790 pm->page = 0;
792 k = get_param_k(pm);
793 kbd_spellchar(pm->kbd_buf[k]);
794 break;
797 #ifdef KBD_MORSE_INPUT
798 case ACTION_KBD_MORSE_INPUT:
799 morse_mode = !morse_mode;
801 FOR_NB_SCREENS(l)
803 struct keyboard_parameters *pm = &param[l];
804 struct screen *sc = &screens[l];
806 pm->x = pm->y = pm->page = 0;
808 if (morse_mode)
810 pm->old_main_y = pm->main_y;
811 pm->main_y = sc->getheight() - pm->font_h;
813 else
815 pm->main_y = pm->old_main_y;
818 /* FIXME: We should talk something like Morse mode.. */
819 break;
820 #endif /* KBD_MORSE_INPUT */
822 case ACTION_KBD_RIGHT:
823 #ifdef KBD_MODES
824 #ifdef KBD_MORSE_INPUT
825 /* allow cursor change in non line edit morse mode */
826 if (pm->line_edit || morse_mode)
827 #else
828 /* right doubles as cursor_right in line_edit */
829 if (pm->line_edit)
830 #endif
832 pm->hangul = false;
834 if (editpos < len_utf8)
836 int c = utf8seek(text, ++editpos);
837 kbd_spellchar(text[c]);
839 #if CONFIG_CODEC == SWCODEC
840 else if (global_settings.talk_menu)
841 pcmbuf_beep(1000, 150, 1500);
842 #endif
844 else
845 #endif /* KBD_MODES */
847 int k;
848 #ifdef KBD_MORSE_INPUT
849 if (morse_mode)
850 break;
851 #endif
852 if (++pm->x >= pm->max_chars)
854 #ifndef KBD_PAGE_FLIP
855 /* no dedicated flip key - flip page on wrap */
856 if (++pm->page >= pm->pages)
857 pm->page = 0;
858 #endif
859 pm->x = 0;
862 k = get_param_k(pm);
863 kbd_spellchar(pm->kbd_buf[k]);
865 break;
867 case ACTION_KBD_LEFT:
868 #ifdef KBD_MODES
869 #ifdef KBD_MORSE_INPUT
870 /* allow cursor change in non line edit morse mode */
871 if (pm->line_edit || morse_mode)
872 #else
873 /* left doubles as cursor_left in line_edit */
874 if (pm->line_edit)
875 #endif
877 pm->hangul = false;
879 if (editpos > 0)
881 int c = utf8seek(text, --editpos);
882 kbd_spellchar(text[c]);
884 #if CONFIG_CODEC == SWCODEC
885 else if (global_settings.talk_menu)
886 pcmbuf_beep(1000, 150, 1500);
887 #endif
889 else
890 #endif /* KBD_MODES */
892 int k;
893 #ifdef KBD_MORSE_INPUT
894 if (morse_mode)
895 break;
896 #endif
897 if (--pm->x < 0)
899 #ifndef KBD_PAGE_FLIP
900 /* no dedicated flip key - flip page on wrap */
901 if (--pm->page < 0)
902 pm->page = pm->pages - 1;
903 #endif
904 pm->x = pm->max_chars - 1;
907 k = get_param_k(pm);
908 kbd_spellchar(pm->kbd_buf[k]);
910 break;
912 case ACTION_KBD_DOWN:
913 #ifdef KBD_MORSE_INPUT
914 #ifdef KBD_MODES
915 if (morse_mode)
917 pm->line_edit = !pm->line_edit;
918 if(pm->line_edit)
919 say_edit();
921 else
922 #else
923 if (morse_mode)
924 break;
925 #endif
926 #endif /* KBD_MORSE_INPUT */
928 #ifdef KBD_MODES
929 if (pm->line_edit)
931 pm->y = 0;
932 pm->line_edit = false;
934 else
935 #endif
936 if (++pm->y >= pm->lines)
937 #ifdef KBD_MODES
939 pm->line_edit = true;
940 say_edit();
942 #else
943 pm->y = 0;
944 #endif
946 #ifdef KBD_MODES
947 if (!pm->line_edit)
948 #endif
950 int k = get_param_k(pm);
951 kbd_spellchar(pm->kbd_buf[k]);
953 break;
955 case ACTION_KBD_UP:
956 #ifdef KBD_MORSE_INPUT
957 #ifdef KBD_MODES
958 if (morse_mode)
960 pm->line_edit = !pm->line_edit;
961 if(pm->line_edit)
962 say_edit();
964 else
965 #else
966 if (morse_mode)
967 break;
968 #endif
969 #endif /* KBD_MORSE_INPUT */
971 #ifdef KBD_MODES
972 if (pm->line_edit)
974 pm->y = pm->lines - 1;
975 pm->line_edit = false;
977 else
978 #endif
979 if (--pm->y < 0)
980 #ifdef KBD_MODES
982 pm->line_edit = true;
983 say_edit();
985 #else
986 pm->y = pm->lines - 1;
987 #endif
989 #ifdef KBD_MODES
990 if (!pm->line_edit)
991 #endif
993 int k = get_param_k(pm);
994 kbd_spellchar(pm->kbd_buf[k]);
996 break;
998 case ACTION_KBD_DONE:
999 /* accepts what was entered and continues */
1000 ret = 0;
1001 done = true;
1002 break;
1004 #ifdef KBD_MORSE_INPUT
1005 case ACTION_KBD_MORSE_SELECT:
1006 if (morse_mode && morse_reading)
1008 morse_code <<= 1;
1009 if ((current_tick - morse_tick) > HZ/5)
1010 morse_code |= 0x01;
1013 break;
1014 #endif /* KBD_MORSE_INPUT */
1016 case ACTION_KBD_SELECT:
1017 case ACTION_KBD_SELECT_REM:
1018 #ifdef KBD_MORSE_INPUT
1019 #ifdef KBD_MODES
1020 if (morse_mode && !pm->line_edit)
1021 #else
1022 if (morse_mode)
1023 #endif
1025 morse_tick = current_tick;
1027 if (!morse_reading)
1029 morse_reading = true;
1030 morse_code = 1;
1032 break;
1034 #endif /* KBD_MORSE_INPUT */
1036 /* inserts the selected char */
1037 #ifdef KBD_MODES
1038 if (pm->line_edit)
1039 { /* select doubles as backspace in line_edit */
1040 if (pm->hangul)
1042 if (pm->htail)
1043 pm->htail = 0;
1044 else if (pm->hvowel)
1045 pm->hvowel = 0;
1046 else
1047 pm->hangul = false;
1050 kbd_delchar(text, &editpos);
1052 if (pm->hangul)
1054 if (pm->hvowel)
1055 ch = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1056 else
1057 ch = pm->hlead;
1058 kbd_inschar(text, buflen, &editpos, ch);
1061 else
1062 #endif /* KBD_MODES */
1064 /* find input char */
1065 int k = get_param_k(pm);
1066 ch = (k < pm->nchars) ? pm->kbd_buf[k] : ' ';
1068 /* check for hangul input */
1069 if (ch >= 0x3131 && ch <= 0x3163)
1071 unsigned short tmp;
1073 if (!pm->hangul)
1075 pm->hlead = pm->hvowel = pm->htail = 0;
1076 pm->hangul = true;
1079 if (!pm->hvowel)
1081 pm->hvowel = ch;
1083 else if (!pm->htail)
1085 pm->htail = ch;
1087 else
1088 { /* previous hangul complete */
1089 /* check whether tail is actually lead of next char */
1090 tmp = hangul_join(pm->htail, ch, 0);
1092 if (tmp != 0xfffd)
1094 tmp = hangul_join(pm->hlead, pm->hvowel, 0);
1095 kbd_delchar(text, &editpos);
1096 kbd_inschar(text, buflen, &editpos, tmp);
1097 /* insert dummy char */
1098 kbd_inschar(text, buflen, &editpos, ' ');
1099 pm->hlead = pm->htail;
1100 pm->hvowel = ch;
1101 pm->htail = 0;
1103 else
1105 pm->hvowel = pm->htail = 0;
1106 pm->hlead = ch;
1110 /* combine into hangul */
1111 tmp = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1113 if (tmp != 0xfffd)
1115 kbd_delchar(text, &editpos);
1116 ch = tmp;
1118 else
1120 pm->hvowel = pm->htail = 0;
1121 pm->hlead = ch;
1124 else
1126 pm->hangul = false;
1129 /* insert char */
1130 kbd_inschar(text, buflen, &editpos, ch);
1133 if (global_settings.talk_menu) /* voice UI? */
1134 talk_spell(text, false);
1136 /* speak revised text */
1137 break;
1139 #if !defined (KBD_MODES) || defined (KBD_CURSOR_KEYS)
1140 case ACTION_KBD_BACKSPACE:
1141 if (pm->hangul)
1143 if (pm->htail)
1144 pm->htail = 0;
1145 else if (pm->hvowel)
1146 pm->hvowel = 0;
1147 else
1148 pm->hangul = false;
1151 kbd_delchar(text, &editpos);
1153 if (pm->hangul)
1155 if (pm->hvowel)
1156 ch = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1157 else
1158 ch = pm->hlead;
1159 kbd_inschar(text, buflen, &editpos, ch);
1162 if (global_settings.talk_menu) /* voice UI? */
1163 talk_spell(text, false); /* speak revised text */
1164 break;
1166 case ACTION_KBD_CURSOR_RIGHT:
1167 pm->hangul = false;
1169 if (editpos < len_utf8)
1171 int c = utf8seek(text, ++editpos);
1172 kbd_spellchar(text[c]);
1174 #if CONFIG_CODEC == SWCODEC
1175 else if (global_settings.talk_menu)
1176 pcmbuf_beep(1000, 150, 1500);
1177 #endif
1178 break;
1180 case ACTION_KBD_CURSOR_LEFT:
1181 pm->hangul = false;
1183 if (editpos > 0)
1185 int c = utf8seek(text, --editpos);
1186 kbd_spellchar(text[c]);
1188 #if CONFIG_CODEC == SWCODEC
1189 else if (global_settings.talk_menu)
1190 pcmbuf_beep(1000, 150, 1500);
1191 #endif
1192 break;
1193 #endif /* !defined (KBD_MODES) || defined (KBD_CURSOR_KEYS) */
1195 case BUTTON_NONE:
1196 #ifdef KBD_MORSE_INPUT
1197 if (morse_reading)
1199 int j;
1200 logf("Morse: 0x%02x", morse_code);
1201 morse_reading = false;
1203 for (j = 0; morse_alphabets[j] != '\0'; j++)
1205 if (morse_codes[j] == morse_code)
1206 break ;
1209 if (morse_alphabets[j] == '\0')
1211 logf("Morse code not found");
1212 break ;
1215 /* turn off hangul input */
1216 FOR_NB_SCREENS(l)
1217 param[l].hangul = false;
1218 kbd_inschar(text, buflen, &editpos, morse_alphabets[j]);
1220 if (global_settings.talk_menu) /* voice UI? */
1221 talk_spell(text, false); /* speak revised text */
1223 #endif /* KBD_MORSE_INPUT */
1224 break;
1226 default:
1227 if (default_event_handler(button) == SYS_USB_CONNECTED)
1229 FOR_NB_SCREENS(l)
1230 screens[l].setfont(FONT_SYSFIXED);
1232 break;
1234 } /* end switch */
1236 if (button != BUTTON_NONE)
1238 cur_blink = true;
1242 #ifdef HAVE_BUTTONBAR
1243 global_settings.buttonbar = buttonbar_config;
1244 #endif
1246 FOR_NB_SCREENS(l)
1247 screens[l].setfont(FONT_UI);
1248 viewportmanager_set_statusbar(oldbars);
1250 if (ret < 0)
1251 splash(HZ/2, ID2P(LANG_CANCEL));
1252 return ret;