E200: Restore the scroll wheel support in brickmania that got lost in the previous...
[Rockbox.git] / apps / recorder / keyboard.c
blob6c75d07a6582a6f5f21acfd3ab4c25958af13bdb
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Björn Stenberg
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "kernel.h"
20 #include "system.h"
21 #include "version.h"
22 #include <string.h>
23 #include "font.h"
24 #include "screens.h"
25 #include "statusbar.h"
26 #include "talk.h"
27 #include "settings.h"
28 #include "misc.h"
29 #include "rbunicode.h"
30 #include "buttonbar.h"
31 #include "logf.h"
32 #include "hangul.h"
33 #include "action.h"
34 #include "icon.h"
35 #include "pcmbuf.h"
36 #include "lang.h"
38 #ifndef O_BINARY
39 #define O_BINARY 0
40 #endif
42 #if CONFIG_KEYPAD == RECORDER_PAD
43 #define BUTTONBAR_HEIGHT 8
44 #else
45 #define BUTTONBAR_HEIGHT 0
46 #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
70 #define KBD_MODES /* iAudio X5 uses 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 #define KBD_CURSOR_KEYS
83 #define KBD_MODES
84 #endif
86 struct keyboard_parameters
88 const unsigned char* default_kbd;
89 int DEFAULT_LINES;
90 unsigned short kbd_buf[KBD_BUF_SIZE];
91 int nchars;
92 int font_w;
93 int font_h;
94 struct font* font;
95 int curfont;
96 int main_x;
97 int main_y;
98 int max_chars;
99 int max_chars_text;
100 int lines;
101 int pages;
102 int keyboard_margin;
103 int old_main_y;
104 int curpos;
105 int leftpos;
106 int page;
107 int x;
108 int y;
109 #ifdef KBD_MODES
110 bool line_edit;
111 #endif
112 bool hangul;
113 unsigned short hlead, hvowel, htail;
116 static struct keyboard_parameters kbd_param[NB_SCREENS];
117 static bool kbd_loaded = false;
119 #ifdef KBD_MORSE_INPUT
120 /* FIXME: We should put this to a configuration file. */
121 static const char *morse_alphabets =
122 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
123 static const unsigned char morse_codes[] = {
124 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
125 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
126 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
127 0x73,0x55,0x4c,0x61,0x5a,0x80 };
129 static bool morse_mode = false;
130 #endif
132 /* Loads a custom keyboard into memory
133 call with NULL to reset keyboard */
134 int load_kbd(unsigned char* filename)
136 int fd, l;
137 int i = 0;
138 unsigned char buf[4];
140 if (filename == NULL)
142 kbd_loaded = false;
143 return 0;
146 fd = open(filename, O_RDONLY|O_BINARY);
147 if (fd < 0)
148 return 1;
150 while (read(fd, buf, 1) == 1 && i < KBD_BUF_SIZE)
152 /* check how many bytes to read for this character */
153 static const unsigned char sizes[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
154 size_t count;
156 for (count = 0; count < ARRAYLEN(sizes); count++)
158 if (buf[0] < sizes[count])
159 break;
162 if (count >= ARRAYLEN(sizes))
163 continue; /* Invalid size. */
165 if (read(fd, &buf[1], count) != (ssize_t)count)
167 close(fd);
168 kbd_loaded = false;
169 return 1;
172 FOR_NB_SCREENS(l)
173 utf8decode(buf, &kbd_param[l].kbd_buf[i]);
175 if (kbd_param[0].kbd_buf[i] != 0xFEFF &&
176 kbd_param[0].kbd_buf[i] != '\r') /*skip BOM & carriage returns */
178 i++;
182 close(fd);
183 kbd_loaded = true;
185 FOR_NB_SCREENS(l)
186 kbd_param[l].nchars = i;
188 return 0;
191 /* helper function to spell a char if voice UI is enabled */
192 static void kbd_spellchar(unsigned short c)
194 if (global_settings.talk_menu) /* voice UI? */
196 unsigned char tmp[5];
197 /* store char to pass to talk_spell */
198 unsigned char* utf8 = utf8encode(c, tmp);
199 *utf8 = 0;
201 if(c == ' ')
202 talk_id(VOICE_BLANK, false);
203 else
204 talk_spell(tmp, false);
208 #ifdef KBD_MODES
209 static void say_edit(void)
211 if(global_settings.talk_menu)
212 talk_id(VOICE_EDIT, false);
214 #endif
216 static void kbd_inschar(unsigned char* text, int buflen,
217 int* editpos, unsigned short ch)
219 int i, j, k, len;
220 unsigned char tmp[4];
221 unsigned char* utf8;
223 len = strlen(text);
224 k = utf8length(text);
225 utf8 = utf8encode(ch, tmp);
226 j = (long)utf8 - (long)tmp;
228 if (len + j < buflen)
230 for (i = len+j; k >= *editpos; i--)
232 text[i] = text[i-j];
233 if ((text[i] & MASK) != COMP)
234 k--;
237 while (j--)
238 text[i--] = tmp[j];
240 (*editpos)++;
244 static void kbd_delchar(unsigned char* text, int* editpos)
246 int i = 0;
247 unsigned char* utf8;
249 if (*editpos > 0)
251 utf8 = text + utf8seek(text, *editpos);
255 i++;
256 utf8--;
258 while ((*utf8 & MASK) == COMP);
260 while (utf8[i])
262 *utf8 = utf8[i];
263 utf8++;
266 *utf8 = 0;
267 (*editpos)--;
271 /* Lookup k value based on state of param (pm) */
272 static int get_param_k(const struct keyboard_parameters *pm)
274 return (pm->page*pm->lines + pm->y)*pm->max_chars + pm->x;
277 int kbd_input(char* text, int buflen)
279 bool done = false;
280 #ifdef CPU_ARM
281 /* This seems to keep the sizes for ARM way down */
282 struct keyboard_parameters * volatile param = kbd_param;
283 #else
284 struct keyboard_parameters * const param = kbd_param;
285 #endif
286 int l; /* screen loop variable */
287 int text_w = 0;
288 int editpos; /* Edit position on all screens */
289 const int statusbar_size = global_settings.statusbar
290 ? STATUSBAR_HEIGHT : 0;
291 unsigned short ch;
292 unsigned char *utf8;
293 bool cur_blink = true; /* Cursor on/off flag */
294 #ifdef KBD_MORSE_INPUT
295 bool morse_reading = false;
296 unsigned char morse_code = 0;
297 int morse_tick = 0;
298 char buf[2];
299 #endif
301 FOR_NB_SCREENS(l)
303 struct keyboard_parameters *pm = &param[l];
304 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96
305 struct screen *sc = &screens[l];
307 if (sc->width >= 160 && sc->height >= 96)
309 pm->default_kbd =
310 "ABCDEFG abcdefg !?\" @#$%+'\n"
311 "HIJKLMN hijklmn 789 &_()-`\n"
312 "OPQRSTU opqrstu 456 §|{}/<\n"
313 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
314 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
315 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
316 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
317 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;";
319 pm->DEFAULT_LINES = 8;
321 else
322 #endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */
324 pm->default_kbd =
325 "ABCDEFG !?\" @#$%+'\n"
326 "HIJKLMN 789 &_()-`\n"
327 "OPQRSTU 456 §|{}/<\n"
328 "VWXYZ.,0123 ~=[]*>\n"
330 "abcdefg ¢£¤¥¦§©®¬\n"
331 "hijklmn «»°ºª¹²³¶\n"
332 "opqrstu ¯±×÷¡¿µ·¨\n"
333 "vwxyz., :;¼½¾ \n"
335 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
336 "àáâãäåæ ìíîï èéêë\n"
337 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
338 "òóôõöø çðþýÿ ùúûü";
340 pm->DEFAULT_LINES = 4;
344 char outline[256];
345 #ifdef HAS_BUTTONBAR
346 struct gui_buttonbar buttonbar;
347 bool buttonbar_config = global_settings.buttonbar;
349 global_settings.buttonbar = true;
350 gui_buttonbar_init(&buttonbar);
352 FOR_NB_SCREENS(l)
353 gui_buttonbar_set_display(&buttonbar, &screens[l]);
354 #endif
356 FOR_NB_SCREENS(l)
358 struct keyboard_parameters *pm = &param[l];
360 if ( !kbd_loaded )
362 /* Copy default keyboard to buffer */
363 const unsigned char *p = pm->default_kbd;
364 int i = 0;
366 pm->curfont = FONT_SYSFIXED;
368 while (*p != 0)
369 p = utf8decode(p, &pm->kbd_buf[i++]);
371 pm->nchars = i;
373 else
375 pm->curfont = FONT_UI;
379 FOR_NB_SCREENS(l)
381 struct keyboard_parameters *pm = &param[l];
382 struct screen *sc = &screens[l];
383 int i, w;
385 pm->font = font_get(pm->curfont);
386 pm->font_h = pm->font->height;
388 /* check if FONT_UI fits the screen */
389 if (2*pm->font_h + 3 + statusbar_size + BUTTONBAR_HEIGHT > sc->height)
391 pm->font = font_get(FONT_SYSFIXED);
392 pm->font_h = pm->font->height;
393 pm->curfont = FONT_SYSFIXED;
396 sc->setfont(pm->curfont);
397 pm->font_w = 0; /* reset font width */
398 /* find max width of keyboard glyphs */
399 for (i = 0; i < pm->nchars; i++)
401 w = font_get_width(pm->font, pm->kbd_buf[i]);
402 if ( w > pm->font_w )
403 pm->font_w = w;
406 /* Since we're going to be adding spaces, make sure that we check
407 * their width too */
408 w = font_get_width( pm->font, ' ' );
409 if ( w > pm->font_w )
410 pm->font_w = w;
413 FOR_NB_SCREENS(l)
415 struct keyboard_parameters *pm = &param[l];
416 struct screen *sc = &screens[l];
417 int i = 0;
419 /* Pad lines with spaces */
420 while (i < pm->nchars)
422 if (pm->kbd_buf[i] == '\n')
424 int k = sc->width / pm->font_w
425 - i % ( sc->width / pm->font_w ) - 1;
426 int j;
428 if (k == sc->width / pm->font_w - 1)
430 pm->nchars--;
432 for (j = i; j < pm->nchars; j++)
434 pm->kbd_buf[j] = pm->kbd_buf[j + 1];
437 else
439 if (pm->nchars + k - 1 >= KBD_BUF_SIZE)
440 { /* We don't want to overflow the buffer */
441 k = KBD_BUF_SIZE - pm->nchars;
444 for (j = pm->nchars + k - 1; j > i + k; j--)
446 pm->kbd_buf[j] = pm->kbd_buf[j-k];
449 pm->nchars += k;
450 k++;
452 while (k--)
454 pm->kbd_buf[i++] = ' ';
458 else
460 i++;
465 /* Find max width for text string */
466 utf8 = text;
467 FOR_NB_SCREENS(l)
469 struct keyboard_parameters *pm = &param[l];
470 struct screen *sc = &screens[l];
472 text_w = pm->font_w;
474 while (*utf8)
476 int w = font_get_width(pm->font, ch);
477 utf8 = (unsigned char*)utf8decode(utf8, &ch);
479 if (w > text_w)
480 text_w = w;
483 pm->max_chars_text = sc->width / text_w - 2;
485 /* Calculate keyboard grid size */
486 pm->max_chars = sc->width / pm->font_w;
488 if (!kbd_loaded)
490 pm->lines = pm->DEFAULT_LINES;
491 pm->keyboard_margin = DEFAULT_MARGIN;
493 else
495 pm->lines = (sc->height - BUTTONBAR_HEIGHT - statusbar_size)
496 / pm->font_h - 1;
497 pm->keyboard_margin = sc->height - BUTTONBAR_HEIGHT -
498 statusbar_size - (pm->lines+1)*pm->font_h;
500 if (pm->keyboard_margin < 3)
502 pm->lines--;
503 pm->keyboard_margin += pm->font_h;
506 if (pm->keyboard_margin > 6)
507 pm->keyboard_margin = 6;
510 pm->pages = (pm->nchars + (pm->lines*pm->max_chars-1))
511 / (pm->lines*pm->max_chars);
513 if (pm->pages == 1 && kbd_loaded)
514 pm->lines = (pm->nchars + pm->max_chars - 1) / pm->max_chars;
516 pm->main_y = pm->font_h*pm->lines + pm->keyboard_margin + statusbar_size;
517 pm->main_x = 0;
518 pm->keyboard_margin -= pm->keyboard_margin/2;
520 #ifdef KBD_MORSE_INPUT
521 pm->old_main_y = pm->main_y;
522 if (morse_mode)
523 pm->main_y = sc->height - pm->font_h;
524 #endif
527 /* Initial edit position is after last character */
528 editpos = utf8length(text);
530 if (global_settings.talk_menu) /* voice UI? */
531 talk_spell(text, true); /* spell initial text */
534 while (!done)
536 /* These declarations are assigned to the screen on which the key
537 action occurred - pointers save a lot of space over array notation
538 when accessing the same array element countless times */
539 int button;
540 #if NB_SCREENS > 1
541 int button_screen;
542 #else
543 const int button_screen = 0;
544 #endif
545 struct keyboard_parameters *pm;
546 struct screen *sc;
548 int len_utf8 = utf8length(text);
550 FOR_NB_SCREENS(l)
551 screens[l].clear_display();
553 #ifdef KBD_MORSE_INPUT
554 if (morse_mode)
556 FOR_NB_SCREENS(l)
558 /* declare scoped pointers inside screen loops - hide the
559 declarations from previous block level */
560 const int w = 6; /* sysfixed font width */
561 struct keyboard_parameters *pm = &param[l];
562 struct screen *sc = &screens[l];
563 int i;
565 sc->setfont(FONT_SYSFIXED); /* Draw morse code screen with sysfont */
566 pm->x = 0;
567 pm->y = statusbar_size;
568 buf[1] = '\0';
570 /* Draw morse code table with code descriptions. */
571 for (i = 0; morse_alphabets[i] != '\0'; i++)
573 int morse_len;
574 int j;
576 buf[0] = morse_alphabets[i];
577 sc->putsxy(pm->x, pm->y, buf);
579 for (j = 0; (morse_codes[i] >> j) > 0x01; j++) ;
580 morse_len = j;
582 pm->x += w + 3;
583 for (j = 0; j < morse_len; j++)
585 if ((morse_codes[i] >> (morse_len-j-1)) & 0x01)
586 sc->fillrect(pm->x + j*4, pm->y + 2, 3, 4);
587 else
588 sc->fillrect(pm->x + j*4, pm->y + 3, 1, 2);
591 pm->x += w*5 - 3;
592 if (pm->x >= sc->width - w*6)
594 pm->x = 0;
595 pm->y += 8; /* sysfixed font height */
600 else
601 #endif /* KBD_MORSE_INPUT */
603 /* draw page */
604 FOR_NB_SCREENS(l)
606 struct keyboard_parameters *pm = &param[l];
607 struct screen *sc = &screens[l];
608 int i, j, k;
610 sc->setfont(pm->curfont);
612 k = pm->page*pm->max_chars*pm->lines;
614 for (i = j = 0; j < pm->lines && k < pm->nchars; k++)
616 int w;
617 utf8 = utf8encode(pm->kbd_buf[k], outline);
618 *utf8 = 0;
620 sc->getstringsize(outline, &w, NULL);
621 sc->putsxy(i*pm->font_w + (pm->font_w-w) / 2,
622 j*pm->font_h + statusbar_size, outline);
624 if (++i >= pm->max_chars)
626 i = 0;
627 j++;
633 /* separator */
634 FOR_NB_SCREENS(l)
636 struct keyboard_parameters *pm = &param[l];
637 struct screen *sc = &screens[l];
638 int i = 0, j = 0;
640 /* Clear text area one pixel above separator line so any overdraw
641 doesn't collide */
642 sc->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
643 sc->fillrect(0, pm->main_y - pm->keyboard_margin - 1,
644 sc->width, pm->font_h + 4);
645 sc->set_drawmode(DRMODE_SOLID);
647 sc->hline(0, sc->width - 1, pm->main_y - pm->keyboard_margin);
649 /* write out the text */
650 sc->setfont(pm->curfont);
652 pm->curpos = MIN(editpos, pm->max_chars_text
653 - MIN(len_utf8 - editpos, 2));
654 pm->leftpos = editpos - pm->curpos;
655 utf8 = text + utf8seek(text, pm->leftpos);
657 text_w = pm->font_w;
659 while (*utf8 && i < pm->max_chars_text)
661 outline[j++] = *utf8++;
663 if ((*utf8 & MASK) != COMP)
665 int w;
666 outline[j] = 0;
667 j=0;
668 i++;
669 sc->getstringsize(outline, &w, NULL);
670 sc->putsxy(i*text_w + (text_w-w)/2, pm->main_y, outline);
674 if (pm->leftpos > 0)
676 /* Draw nicer bitmap arrow if room, else settle for "<". */
677 if (text_w >= 6 && pm->font_h >= 8)
679 screen_put_iconxy(sc, (text_w - 6) / 2,
680 pm->main_y + (pm->font_h - 8) / 2 ,
681 Icon_Reverse_Cursor);
683 else
685 int w;
686 sc->getstringsize("<", &w, NULL);
687 sc->putsxy(text_w - w, pm->main_y, "<");
691 if (len_utf8 - pm->leftpos > pm->max_chars_text)
693 /* Draw nicer bitmap arrow if room, else settle for ">". */
694 if (text_w >= 6 && pm->font_h >= 8)
696 screen_put_iconxy(sc, sc->width - text_w + (text_w - 6) / 2,
697 pm->main_y + (pm->font_h - 8) / 2,
698 Icon_Cursor);
700 else
702 sc->putsxy(sc->width - text_w, pm->main_y, ">");
706 /* cursor */
707 i = (pm->curpos + 1) * text_w;
709 if (cur_blink)
710 sc->vline(i, pm->main_y, pm->main_y + pm->font_h - 1);
712 if (pm->hangul) /* draw underbar */
713 sc->hline(pm->curpos*text_w, (pm->curpos+1)*text_w,
714 pm->main_y + pm->font_h - 1);
717 cur_blink = !cur_blink;
719 #ifdef HAS_BUTTONBAR
720 /* draw the button bar */
721 gui_buttonbar_set(&buttonbar, "Shift", "OK", "Del");
722 gui_buttonbar_draw(&buttonbar);
723 #endif
725 FOR_NB_SCREENS(l)
727 struct keyboard_parameters *pm = &param[l];
728 struct screen *sc = &screens[l];
730 sc->set_drawmode(DRMODE_COMPLEMENT);
731 #ifdef KBD_MODES
732 if (pm->line_edit)
733 sc->fillrect(0, pm->main_y - pm->keyboard_margin + 2,
734 sc->width, pm->font_h + 2);
735 else /* highlight the key that has focus */
736 #endif
737 sc->fillrect(pm->font_w*pm->x,
738 statusbar_size + pm->font_h*pm->y,
739 pm->font_w, pm->font_h);
740 sc->set_drawmode(DRMODE_SOLID);
743 gui_syncstatusbar_draw(&statusbars, true);
744 FOR_NB_SCREENS(l)
745 screens[l].update();
747 button = get_action(CONTEXT_KEYBOARD, HZ/2);
748 #if NB_SCREENS > 1
749 button_screen = (get_action_statuscode(NULL) & ACTION_REMOTE) ? 1 : 0;
750 #endif
751 pm = &param[button_screen];
752 sc = &screens[button_screen];
754 #if defined KBD_MORSE_INPUT && !defined KBD_MODES
755 if (morse_mode)
757 /* Remap some buttons for morse mode. */
758 if (button == ACTION_KBD_LEFT)
759 button = ACTION_KBD_CURSOR_LEFT;
760 if (button == ACTION_KBD_RIGHT)
761 button = ACTION_KBD_CURSOR_RIGHT;
763 #endif
765 switch ( button )
767 case ACTION_KBD_ABORT:
768 FOR_NB_SCREENS(l)
769 screens[l].setfont(FONT_UI);
771 #ifdef HAS_BUTTONBAR
772 global_settings.buttonbar=buttonbar_config;
773 #endif
774 return -1;
775 break;
777 case ACTION_KBD_PAGE_FLIP:
779 int k;
780 #ifdef KBD_MORSE_INPUT
781 if (morse_mode)
782 break;
783 #endif
784 if (++pm->page >= pm->pages)
785 pm->page = 0;
787 k = get_param_k(pm);
788 kbd_spellchar(pm->kbd_buf[k]);
789 break;
792 #ifdef KBD_MORSE_INPUT
793 case ACTION_KBD_MORSE_INPUT:
794 morse_mode = !morse_mode;
796 FOR_NB_SCREENS(l)
798 struct keyboard_parameters *pm = &param[l];
799 struct screen *sc = &screens[l];
801 pm->x = pm->y = pm->page = 0;
803 if (morse_mode)
805 pm->old_main_y = pm->main_y;
806 pm->main_y = sc->height - pm->font_h;
808 else
810 pm->main_y = pm->old_main_y;
813 /* FIXME: We should talk something like Morse mode.. */
814 break;
815 #endif /* KBD_MORSE_INPUT */
817 case ACTION_KBD_RIGHT:
818 #ifdef KBD_MODES
819 #ifdef KBD_MORSE_INPUT
820 /* allow cursor change in non line edit morse mode */
821 if (pm->line_edit || morse_mode)
822 #else
823 /* right doubles as cursor_right in line_edit */
824 if (pm->line_edit)
825 #endif
827 pm->hangul = false;
829 if (editpos < len_utf8)
831 int c = utf8seek(text, ++editpos);
832 kbd_spellchar(text[c]);
834 #if CONFIG_CODEC == SWCODEC
835 else if (global_settings.talk_menu)
836 pcmbuf_beep(1000, 150, 1500);
837 #endif
839 else
840 #endif /* KBD_MODES */
842 int k;
843 #ifdef KBD_MORSE_INPUT
844 if (morse_mode)
845 break;
846 #endif
847 if (++pm->x >= pm->max_chars)
849 #ifndef KBD_PAGE_FLIP
850 /* no dedicated flip key - flip page on wrap */
851 if (++pm->page >= pm->pages)
852 pm->page = 0;
853 #endif
854 pm->x = 0;
857 k = get_param_k(pm);
858 kbd_spellchar(pm->kbd_buf[k]);
860 break;
862 case ACTION_KBD_LEFT:
863 #ifdef KBD_MODES
864 #ifdef KBD_MORSE_INPUT
865 /* allow cursor change in non line edit morse mode */
866 if (pm->line_edit || morse_mode)
867 #else
868 /* left doubles as cursor_left in line_edit */
869 if (pm->line_edit)
870 #endif
872 pm->hangul = false;
874 if (editpos > 0)
876 int c = utf8seek(text, --editpos);
877 kbd_spellchar(text[c]);
879 #if CONFIG_CODEC == SWCODEC
880 else if (global_settings.talk_menu)
881 pcmbuf_beep(1000, 150, 1500);
882 #endif
884 else
885 #endif /* KBD_MODES */
887 int k;
888 #ifdef KBD_MORSE_INPUT
889 if (morse_mode)
890 break;
891 #endif
892 if (--pm->x < 0)
894 #ifndef KBD_PAGE_FLIP
895 /* no dedicated flip key - flip page on wrap */
896 if (--pm->page < 0)
897 pm->page = pm->pages - 1;
898 #endif
899 pm->x = pm->max_chars - 1;
902 k = get_param_k(pm);
903 kbd_spellchar(pm->kbd_buf[k]);
905 break;
907 case ACTION_KBD_DOWN:
908 #ifdef KBD_MORSE_INPUT
909 #ifdef KBD_MODES
910 if (morse_mode)
912 pm->line_edit = !pm->line_edit;
913 if(pm->line_edit)
914 say_edit();
916 else
917 #else
918 if (morse_mode)
919 break;
920 #endif
921 #endif /* KBD_MORSE_INPUT */
923 #ifdef KBD_MODES
924 if (pm->line_edit)
926 pm->y = 0;
927 pm->line_edit = false;
929 else
930 #endif
931 if (++pm->y >= pm->lines)
932 #ifdef KBD_MODES
934 pm->line_edit = true;
935 say_edit();
937 #else
938 pm->y = 0;
939 #endif
941 #ifdef KBD_MODES
942 if (!pm->line_edit)
943 #endif
945 int k = get_param_k(pm);
946 kbd_spellchar(pm->kbd_buf[k]);
948 break;
950 case ACTION_KBD_UP:
951 #ifdef KBD_MORSE_INPUT
952 #ifdef KBD_MODES
953 if (morse_mode)
955 pm->line_edit = !pm->line_edit;
956 if(pm->line_edit)
957 say_edit();
959 else
960 #else
961 if (morse_mode)
962 break;
963 #endif
964 #endif /* KBD_MORSE_INPUT */
966 #ifdef KBD_MODES
967 if (pm->line_edit)
969 pm->y = pm->lines - 1;
970 pm->line_edit = false;
972 else
973 #endif
974 if (--pm->y < 0)
975 #ifdef KBD_MODES
977 pm->line_edit = true;
978 say_edit();
980 #else
981 pm->y = pm->lines - 1;
982 #endif
984 #ifdef KBD_MODES
985 if (!pm->line_edit)
986 #endif
988 int k = get_param_k(pm);
989 kbd_spellchar(pm->kbd_buf[k]);
991 break;
993 case ACTION_KBD_DONE:
994 /* accepts what was entered and continues */
995 done = true;
996 break;
998 #ifdef KBD_MORSE_INPUT
999 case ACTION_KBD_MORSE_SELECT:
1000 if (morse_mode && morse_reading)
1002 morse_code <<= 1;
1003 if ((current_tick - morse_tick) > HZ/5)
1004 morse_code |= 0x01;
1007 break;
1008 #endif /* KBD_MORSE_INPUT */
1010 case ACTION_KBD_SELECT:
1011 case ACTION_KBD_SELECT_REM:
1012 #ifdef KBD_MORSE_INPUT
1013 #ifdef KBD_MODES
1014 if (morse_mode && !pm->line_edit)
1015 #else
1016 if (morse_mode)
1017 #endif
1019 morse_tick = current_tick;
1021 if (!morse_reading)
1023 morse_reading = true;
1024 morse_code = 1;
1026 break;
1028 #endif /* KBD_MORSE_INPUT */
1030 /* inserts the selected char */
1031 #ifdef KBD_MODES
1032 if (pm->line_edit)
1033 { /* select doubles as backspace in line_edit */
1034 if (pm->hangul)
1036 if (pm->htail)
1037 pm->htail = 0;
1038 else if (pm->hvowel)
1039 pm->hvowel = 0;
1040 else
1041 pm->hangul = false;
1044 kbd_delchar(text, &editpos);
1046 if (pm->hangul)
1048 if (pm->hvowel)
1049 ch = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1050 else
1051 ch = pm->hlead;
1052 kbd_inschar(text, buflen, &editpos, ch);
1055 else
1056 #endif /* KBD_MODES */
1058 /* find input char */
1059 int k = get_param_k(pm);
1060 ch = (k < pm->nchars) ? pm->kbd_buf[k] : ' ';
1062 /* check for hangul input */
1063 if (ch >= 0x3131 && ch <= 0x3163)
1065 unsigned short tmp;
1067 if (!pm->hangul)
1069 pm->hlead = pm->hvowel = pm->htail = 0;
1070 pm->hangul = true;
1073 if (!pm->hvowel)
1075 pm->hvowel = ch;
1077 else if (!pm->htail)
1079 pm->htail = ch;
1081 else
1082 { /* previous hangul complete */
1083 /* check whether tail is actually lead of next char */
1084 tmp = hangul_join(pm->htail, ch, 0);
1086 if (tmp != 0xfffd)
1088 tmp = hangul_join(pm->hlead, pm->hvowel, 0);
1089 kbd_delchar(text, &editpos);
1090 kbd_inschar(text, buflen, &editpos, tmp);
1091 /* insert dummy char */
1092 kbd_inschar(text, buflen, &editpos, ' ');
1093 pm->hlead = pm->htail;
1094 pm->hvowel = ch;
1095 pm->htail = 0;
1097 else
1099 pm->hvowel = pm->htail = 0;
1100 pm->hlead = ch;
1104 /* combine into hangul */
1105 tmp = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1107 if (tmp != 0xfffd)
1109 kbd_delchar(text, &editpos);
1110 ch = tmp;
1112 else
1114 pm->hvowel = pm->htail = 0;
1115 pm->hlead = ch;
1118 else
1120 pm->hangul = false;
1123 /* insert char */
1124 kbd_inschar(text, buflen, &editpos, ch);
1127 if (global_settings.talk_menu) /* voice UI? */
1128 talk_spell(text, false);
1130 /* speak revised text */
1131 break;
1133 #if !defined (KBD_MODES) || defined (KBD_CURSOR_KEYS)
1134 case ACTION_KBD_BACKSPACE:
1135 if (pm->hangul)
1137 if (pm->htail)
1138 pm->htail = 0;
1139 else if (pm->hvowel)
1140 pm->hvowel = 0;
1141 else
1142 pm->hangul = false;
1145 kbd_delchar(text, &editpos);
1147 if (pm->hangul)
1149 if (pm->hvowel)
1150 ch = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1151 else
1152 ch = pm->hlead;
1153 kbd_inschar(text, buflen, &editpos, ch);
1156 if (global_settings.talk_menu) /* voice UI? */
1157 talk_spell(text, false); /* speak revised text */
1158 break;
1160 case ACTION_KBD_CURSOR_RIGHT:
1161 pm->hangul = false;
1163 if (editpos < len_utf8)
1165 int c = utf8seek(text, ++editpos);
1166 kbd_spellchar(text[c]);
1168 #if CONFIG_CODEC == SWCODEC
1169 else if (global_settings.talk_menu)
1170 pcmbuf_beep(1000, 150, 1500);
1171 #endif
1172 break;
1174 case ACTION_KBD_CURSOR_LEFT:
1175 pm->hangul = false;
1177 if (editpos > 0)
1179 int c = utf8seek(text, --editpos);
1180 kbd_spellchar(text[c]);
1182 #if CONFIG_CODEC == SWCODEC
1183 else if (global_settings.talk_menu)
1184 pcmbuf_beep(1000, 150, 1500);
1185 #endif
1186 break;
1187 #endif /* !defined (KBD_MODES) || defined (KBD_CURSOR_KEYS) */
1189 case BUTTON_NONE:
1190 gui_syncstatusbar_draw(&statusbars, false);
1191 #ifdef KBD_MORSE_INPUT
1192 if (morse_reading)
1194 int j;
1195 logf("Morse: 0x%02x", morse_code);
1196 morse_reading = false;
1198 for (j = 0; morse_alphabets[j] != '\0'; j++)
1200 if (morse_codes[j] == morse_code)
1201 break ;
1204 if (morse_alphabets[j] == '\0')
1206 logf("Morse code not found");
1207 break ;
1210 /* turn off hangul input */
1211 FOR_NB_SCREENS(l)
1212 param[l].hangul = false;
1213 kbd_inschar(text, buflen, &editpos, morse_alphabets[j]);
1215 if (global_settings.talk_menu) /* voice UI? */
1216 talk_spell(text, false); /* speak revised text */
1218 #endif /* KBD_MORSE_INPUT */
1219 break;
1221 default:
1222 if (default_event_handler(button) == SYS_USB_CONNECTED)
1224 FOR_NB_SCREENS(l)
1225 screens[l].setfont(FONT_SYSFIXED);
1227 break;
1229 } /* end switch */
1231 if (button != BUTTON_NONE)
1233 cur_blink = true;
1237 #ifdef HAS_BUTTONBAR
1238 global_settings.buttonbar = buttonbar_config;
1239 #endif
1241 FOR_NB_SCREENS(l)
1242 screens[l].setfont(FONT_UI);
1244 return 0;