Fix FS #9128: invalidate the peakmeter scales when switching between playback and...
[Rockbox.git] / apps / recorder / keyboard.c
bloba15b4cc3463054877965a58ecbd719f2530817f5
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 "statusbar.h"
28 #include "talk.h"
29 #include "settings.h"
30 #include "misc.h"
31 #include "rbunicode.h"
32 #include "buttonbar.h"
33 #include "logf.h"
34 #include "hangul.h"
35 #include "action.h"
36 #include "icon.h"
37 #include "pcmbuf.h"
38 #include "lang.h"
39 #include "keyboard.h"
41 #ifndef O_BINARY
42 #define O_BINARY 0
43 #endif
46 #define DEFAULT_MARGIN 6
47 #define KBD_BUF_SIZE 500
49 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
50 (CONFIG_KEYPAD == IRIVER_H300_PAD)
51 #define KBD_CURSOR_KEYS /* certain key combos move the cursor even if not
52 in line edit mode */
53 #define KBD_MODES /* I-Rivers can use picker, line edit and cursor keys */
54 #define KBD_MORSE_INPUT /* I-Rivers have a Morse input mode */
56 #elif CONFIG_KEYPAD == ONDIO_PAD /* restricted Ondio keypad */
57 #define KBD_MODES /* Ondio uses 2 modes, picker and line edit */
59 #elif (CONFIG_KEYPAD == IPOD_1G2G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) \
60 || (CONFIG_KEYPAD == IPOD_4G_PAD)
61 #define KBD_MODES /* iPod uses 2 modes, picker and line edit */
62 #define KBD_MORSE_INPUT
64 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
65 #define KBD_MODES /* iFP7xx uses 2 modes, picker and line edit */
67 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) || (CONFIG_KEYPAD == IAUDIO_M3_PAD)
68 #define KBD_MODES /* iAudios use 2 modes, picker and line edit */
70 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
71 #define KBD_MODES /* iriver H10 uses 2 modes, picker and line edit */
72 #define KBD_MORSE_INPUT
74 #elif CONFIG_KEYPAD == GIGABEAT_PAD
75 #define KBD_CURSOR_KEYS
76 #define KBD_MODES
77 #define KBD_MORSE_INPUT
79 #elif CONFIG_KEYPAD == SANSA_E200_PAD
80 #define KBD_CURSOR_KEYS
81 #define KBD_MODES
82 #endif
84 struct keyboard_parameters
86 const unsigned char* default_kbd;
87 int DEFAULT_LINES;
88 unsigned short kbd_buf[KBD_BUF_SIZE];
89 int nchars;
90 int font_w;
91 int font_h;
92 struct font* font;
93 int curfont;
94 int main_x;
95 int main_y;
96 int max_chars;
97 int max_chars_text;
98 int lines;
99 int pages;
100 int keyboard_margin;
101 int old_main_y;
102 int curpos;
103 int leftpos;
104 int page;
105 int x;
106 int y;
107 #ifdef KBD_MODES
108 bool line_edit;
109 #endif
110 bool hangul;
111 unsigned short hlead, hvowel, htail;
114 static struct keyboard_parameters kbd_param[NB_SCREENS];
115 static bool kbd_loaded = false;
117 #ifdef KBD_MORSE_INPUT
118 /* FIXME: We should put this to a configuration file. */
119 static const char *morse_alphabets =
120 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
121 static const unsigned char morse_codes[] = {
122 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
123 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
124 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
125 0x73,0x55,0x4c,0x61,0x5a,0x80 };
127 static bool morse_mode = false;
128 #endif
130 /* Loads a custom keyboard into memory
131 call with NULL to reset keyboard */
132 int load_kbd(unsigned char* filename)
134 int fd, l;
135 int i = 0;
136 unsigned char buf[4];
138 if (filename == NULL)
140 kbd_loaded = false;
141 return 0;
144 fd = open(filename, O_RDONLY|O_BINARY);
145 if (fd < 0)
146 return 1;
148 while (read(fd, buf, 1) == 1 && i < KBD_BUF_SIZE)
150 /* check how many bytes to read for this character */
151 static const unsigned char sizes[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
152 size_t count;
154 for (count = 0; count < ARRAYLEN(sizes); count++)
156 if (buf[0] < sizes[count])
157 break;
160 if (count >= ARRAYLEN(sizes))
161 continue; /* Invalid size. */
163 if (read(fd, &buf[1], count) != (ssize_t)count)
165 close(fd);
166 kbd_loaded = false;
167 return 1;
170 FOR_NB_SCREENS(l)
171 utf8decode(buf, &kbd_param[l].kbd_buf[i]);
173 if (kbd_param[0].kbd_buf[i] != 0xFEFF &&
174 kbd_param[0].kbd_buf[i] != '\r') /*skip BOM & carriage returns */
176 i++;
180 close(fd);
181 kbd_loaded = true;
183 FOR_NB_SCREENS(l)
184 kbd_param[l].nchars = i;
186 return 0;
189 /* helper function to spell a char if voice UI is enabled */
190 static void kbd_spellchar(unsigned short c)
192 if (global_settings.talk_menu) /* voice UI? */
194 unsigned char tmp[5];
195 /* store char to pass to talk_spell */
196 unsigned char* utf8 = utf8encode(c, tmp);
197 *utf8 = 0;
199 if(c == ' ')
200 talk_id(VOICE_BLANK, false);
201 else
202 talk_spell(tmp, false);
206 #ifdef KBD_MODES
207 static void say_edit(void)
209 if(global_settings.talk_menu)
210 talk_id(VOICE_EDIT, false);
212 #endif
214 static void kbd_inschar(unsigned char* text, int buflen,
215 int* editpos, unsigned short ch)
217 int i, j, k, len;
218 unsigned char tmp[4];
219 unsigned char* utf8;
221 len = strlen(text);
222 k = utf8length(text);
223 utf8 = utf8encode(ch, tmp);
224 j = (long)utf8 - (long)tmp;
226 if (len + j < buflen)
228 for (i = len+j; k >= *editpos; i--)
230 text[i] = text[i-j];
231 if ((text[i] & MASK) != COMP)
232 k--;
235 while (j--)
236 text[i--] = tmp[j];
238 (*editpos)++;
242 static void kbd_delchar(unsigned char* text, int* editpos)
244 int i = 0;
245 unsigned char* utf8;
247 if (*editpos > 0)
249 utf8 = text + utf8seek(text, *editpos);
253 i++;
254 utf8--;
256 while ((*utf8 & MASK) == COMP);
258 while (utf8[i])
260 *utf8 = utf8[i];
261 utf8++;
264 *utf8 = 0;
265 (*editpos)--;
269 /* Lookup k value based on state of param (pm) */
270 static int get_param_k(const struct keyboard_parameters *pm)
272 return (pm->page*pm->lines + pm->y)*pm->max_chars + pm->x;
275 int kbd_input(char* text, int buflen)
277 bool done = false;
278 #ifdef CPU_ARM
279 /* This seems to keep the sizes for ARM way down */
280 struct keyboard_parameters * volatile param = kbd_param;
281 #else
282 struct keyboard_parameters * const param = kbd_param;
283 #endif
284 int l; /* screen loop variable */
285 int text_w = 0;
286 int editpos; /* Edit position on all screens */
287 const int statusbar_size = global_settings.statusbar
288 ? STATUSBAR_HEIGHT : 0;
289 unsigned short ch;
290 unsigned char *utf8;
291 bool cur_blink = true; /* Cursor on/off flag */
292 #ifdef KBD_MORSE_INPUT
293 bool morse_reading = false;
294 unsigned char morse_code = 0;
295 int morse_tick = 0;
296 char buf[2];
297 #endif
299 FOR_NB_SCREENS(l)
301 struct keyboard_parameters *pm = &param[l];
302 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96
303 struct screen *sc = &screens[l];
305 if (sc->getwidth() >= 160 && sc->getheight() >= 96)
307 pm->default_kbd =
308 "ABCDEFG abcdefg !?\" @#$%+'\n"
309 "HIJKLMN hijklmn 789 &_()-`\n"
310 "OPQRSTU opqrstu 456 §|{}/<\n"
311 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
312 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
313 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
314 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
315 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;";
317 pm->DEFAULT_LINES = 8;
319 else
320 #endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */
322 pm->default_kbd =
323 "ABCDEFG !?\" @#$%+'\n"
324 "HIJKLMN 789 &_()-`\n"
325 "OPQRSTU 456 §|{}/<\n"
326 "VWXYZ.,0123 ~=[]*>\n"
328 "abcdefg ¢£¤¥¦§©®¬\n"
329 "hijklmn «»°ºª¹²³¶\n"
330 "opqrstu ¯±×÷¡¿µ·¨\n"
331 "vwxyz., :;¼½¾ \n"
333 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
334 "àáâãäåæ ìíîï èéêë\n"
335 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
336 "òóôõöø çðþýÿ ùúûü";
338 pm->DEFAULT_LINES = 4;
342 char outline[256];
343 #ifdef HAVE_BUTTONBAR
344 struct gui_buttonbar buttonbar;
345 bool buttonbar_config = global_settings.buttonbar;
347 global_settings.buttonbar = true;
348 gui_buttonbar_init(&buttonbar);
350 FOR_NB_SCREENS(l)
351 gui_buttonbar_set_display(&buttonbar, &screens[l]);
352 #endif
354 FOR_NB_SCREENS(l)
356 struct keyboard_parameters *pm = &param[l];
358 if ( !kbd_loaded )
360 /* Copy default keyboard to buffer */
361 const unsigned char *p = pm->default_kbd;
362 int i = 0;
364 pm->curfont = FONT_SYSFIXED;
366 while (*p != 0)
367 p = utf8decode(p, &pm->kbd_buf[i++]);
369 pm->nchars = i;
371 else
373 pm->curfont = FONT_UI;
377 FOR_NB_SCREENS(l)
379 struct keyboard_parameters *pm = &param[l];
380 struct screen *sc = &screens[l];
381 int i, w;
383 pm->font = font_get(pm->curfont);
384 pm->font_h = pm->font->height;
386 /* check if FONT_UI fits the screen */
387 if (2*pm->font_h + 3 + statusbar_size +
388 BUTTONBAR_HEIGHT > sc->getheight())
390 pm->font = font_get(FONT_SYSFIXED);
391 pm->font_h = pm->font->height;
392 pm->curfont = FONT_SYSFIXED;
395 sc->setfont(pm->curfont);
396 pm->font_w = 0; /* reset font width */
397 /* find max width of keyboard glyphs */
398 for (i = 0; i < pm->nchars; i++)
400 w = font_get_width(pm->font, pm->kbd_buf[i]);
401 if ( w > pm->font_w )
402 pm->font_w = w;
405 /* Since we're going to be adding spaces, make sure that we check
406 * their width too */
407 w = font_get_width( pm->font, ' ' );
408 if ( w > pm->font_w )
409 pm->font_w = w;
412 FOR_NB_SCREENS(l)
414 struct keyboard_parameters *pm = &param[l];
415 struct screen *sc = &screens[l];
416 int i = 0;
418 /* Pad lines with spaces */
419 while (i < pm->nchars)
421 if (pm->kbd_buf[i] == '\n')
423 int k = sc->getwidth() / pm->font_w
424 - i % ( sc->getwidth() / pm->font_w ) - 1;
425 int j;
427 if (k == sc->getwidth() / pm->font_w - 1)
429 pm->nchars--;
431 for (j = i; j < pm->nchars; j++)
433 pm->kbd_buf[j] = pm->kbd_buf[j + 1];
436 else
438 if (pm->nchars + k - 1 >= KBD_BUF_SIZE)
439 { /* We don't want to overflow the buffer */
440 k = KBD_BUF_SIZE - pm->nchars;
443 for (j = pm->nchars + k - 1; j > i + k; j--)
445 pm->kbd_buf[j] = pm->kbd_buf[j-k];
448 pm->nchars += k;
449 k++;
451 while (k--)
453 pm->kbd_buf[i++] = ' ';
457 else
459 i++;
464 /* Find max width for text string */
465 utf8 = text;
466 FOR_NB_SCREENS(l)
468 struct keyboard_parameters *pm = &param[l];
469 struct screen *sc = &screens[l];
471 text_w = pm->font_w;
473 while (*utf8)
475 int w = font_get_width(pm->font, ch);
476 utf8 = (unsigned char*)utf8decode(utf8, &ch);
478 if (w > text_w)
479 text_w = w;
482 pm->max_chars_text = sc->getwidth() / text_w - 2;
484 /* Calculate keyboard grid size */
485 pm->max_chars = sc->getwidth() / pm->font_w;
487 if (!kbd_loaded)
489 pm->lines = pm->DEFAULT_LINES;
490 pm->keyboard_margin = DEFAULT_MARGIN;
492 else
494 pm->lines = (sc->getheight() - BUTTONBAR_HEIGHT - statusbar_size)
495 / pm->font_h - 1;
496 pm->keyboard_margin = sc->getheight() - BUTTONBAR_HEIGHT -
497 statusbar_size - (pm->lines+1)*pm->font_h;
499 if (pm->keyboard_margin < 3)
501 pm->lines--;
502 pm->keyboard_margin += pm->font_h;
505 if (pm->keyboard_margin > 6)
506 pm->keyboard_margin = 6;
509 pm->pages = (pm->nchars + (pm->lines*pm->max_chars-1))
510 / (pm->lines*pm->max_chars);
512 if (pm->pages == 1 && kbd_loaded)
513 pm->lines = (pm->nchars + pm->max_chars - 1) / pm->max_chars;
515 pm->main_y = pm->font_h*pm->lines + pm->keyboard_margin + statusbar_size;
516 pm->main_x = 0;
517 pm->keyboard_margin -= pm->keyboard_margin/2;
519 #ifdef KBD_MORSE_INPUT
520 pm->old_main_y = pm->main_y;
521 if (morse_mode)
522 pm->main_y = sc->getheight() - pm->font_h;
523 #endif
526 /* Initial edit position is after last character */
527 editpos = utf8length(text);
529 if (global_settings.talk_menu) /* voice UI? */
530 talk_spell(text, true); /* spell initial text */
533 while (!done)
535 /* These declarations are assigned to the screen on which the key
536 action occurred - pointers save a lot of space over array notation
537 when accessing the same array element countless times */
538 int button;
539 #if NB_SCREENS > 1
540 int button_screen;
541 #else
542 const int button_screen = 0;
543 #endif
544 struct keyboard_parameters *pm;
545 struct screen *sc;
547 int len_utf8 = utf8length(text);
549 FOR_NB_SCREENS(l)
550 screens[l].clear_display();
552 #ifdef KBD_MORSE_INPUT
553 if (morse_mode)
555 FOR_NB_SCREENS(l)
557 /* declare scoped pointers inside screen loops - hide the
558 declarations from previous block level */
559 const int w = 6; /* sysfixed font width */
560 struct keyboard_parameters *pm = &param[l];
561 struct screen *sc = &screens[l];
562 int i;
564 sc->setfont(FONT_SYSFIXED); /* Draw morse code screen with sysfont */
565 pm->x = 0;
566 pm->y = statusbar_size;
567 buf[1] = '\0';
569 /* Draw morse code table with code descriptions. */
570 for (i = 0; morse_alphabets[i] != '\0'; i++)
572 int morse_len;
573 int j;
575 buf[0] = morse_alphabets[i];
576 sc->putsxy(pm->x, pm->y, buf);
578 for (j = 0; (morse_codes[i] >> j) > 0x01; j++) ;
579 morse_len = j;
581 pm->x += w + 3;
582 for (j = 0; j < morse_len; j++)
584 if ((morse_codes[i] >> (morse_len-j-1)) & 0x01)
585 sc->fillrect(pm->x + j*4, pm->y + 2, 3, 4);
586 else
587 sc->fillrect(pm->x + j*4, pm->y + 3, 1, 2);
590 pm->x += w*5 - 3;
591 if (pm->x >= sc->getwidth() - w*6)
593 pm->x = 0;
594 pm->y += 8; /* sysfixed font height */
599 else
600 #endif /* KBD_MORSE_INPUT */
602 /* draw page */
603 FOR_NB_SCREENS(l)
605 struct keyboard_parameters *pm = &param[l];
606 struct screen *sc = &screens[l];
607 int i, j, k;
609 sc->setfont(pm->curfont);
611 k = pm->page*pm->max_chars*pm->lines;
613 for (i = j = 0; j < pm->lines && k < pm->nchars; k++)
615 int w;
616 utf8 = utf8encode(pm->kbd_buf[k], outline);
617 *utf8 = 0;
619 sc->getstringsize(outline, &w, NULL);
620 sc->putsxy(i*pm->font_w + (pm->font_w-w) / 2,
621 j*pm->font_h + statusbar_size, outline);
623 if (++i >= pm->max_chars)
625 i = 0;
626 j++;
632 /* separator */
633 FOR_NB_SCREENS(l)
635 struct keyboard_parameters *pm = &param[l];
636 struct screen *sc = &screens[l];
637 int i = 0, j = 0;
639 /* Clear text area one pixel above separator line so any overdraw
640 doesn't collide */
641 sc->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
642 sc->fillrect(0, pm->main_y - pm->keyboard_margin - 1,
643 sc->getwidth(), pm->font_h + 4);
644 sc->set_drawmode(DRMODE_SOLID);
646 sc->hline(0, sc->getwidth() - 1, pm->main_y - pm->keyboard_margin);
648 /* write out the text */
649 sc->setfont(pm->curfont);
651 pm->curpos = MIN(editpos, pm->max_chars_text
652 - MIN(len_utf8 - editpos, 2));
653 pm->leftpos = editpos - pm->curpos;
654 utf8 = text + utf8seek(text, pm->leftpos);
656 text_w = pm->font_w;
658 while (*utf8 && i < pm->max_chars_text)
660 outline[j++] = *utf8++;
662 if ((*utf8 & MASK) != COMP)
664 int w;
665 outline[j] = 0;
666 j=0;
667 i++;
668 sc->getstringsize(outline, &w, NULL);
669 sc->putsxy(i*text_w + (text_w-w)/2, pm->main_y, outline);
673 if (pm->leftpos > 0)
675 /* Draw nicer bitmap arrow if room, else settle for "<". */
676 if (text_w >= 6 && pm->font_h >= 8)
678 screen_put_iconxy(sc, (text_w - 6) / 2,
679 pm->main_y + (pm->font_h - 8) / 2 ,
680 Icon_Reverse_Cursor);
682 else
684 int w;
685 sc->getstringsize("<", &w, NULL);
686 sc->putsxy(text_w - w, pm->main_y, "<");
690 if (len_utf8 - pm->leftpos > pm->max_chars_text)
692 /* Draw nicer bitmap arrow if room, else settle for ">". */
693 if (text_w >= 6 && pm->font_h >= 8)
695 screen_put_iconxy(sc, sc->getwidth() - text_w +
696 (text_w - 6) / 2,
697 pm->main_y + (pm->font_h - 8) / 2,
698 Icon_Cursor);
700 else
702 sc->putsxy(sc->getwidth() - 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 HAVE_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->getwidth(), 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 HAVE_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->getheight() - 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 HAVE_BUTTONBAR
1238 global_settings.buttonbar = buttonbar_config;
1239 #endif
1241 FOR_NB_SCREENS(l)
1242 screens[l].setfont(FONT_UI);
1244 return 0;