Don't objcopy simulator plugins.
[kugel-rb.git] / apps / recorder / keyboard.c
blobf72def6a8a53f680ba38d9c35ba68b20fce506fb
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
83 #elif CONFIG_KEYPAD == MROBE100_PAD
84 #define KBD_MORSE_INPUT
85 #endif
87 struct keyboard_parameters
89 const unsigned char* default_kbd;
90 int DEFAULT_LINES;
91 unsigned short kbd_buf[KBD_BUF_SIZE];
92 int nchars;
93 int font_w;
94 int font_h;
95 struct font* font;
96 int curfont;
97 int main_x;
98 int main_y;
99 int max_chars;
100 int max_chars_text;
101 int lines;
102 int pages;
103 int keyboard_margin;
104 int old_main_y;
105 int curpos;
106 int leftpos;
107 int page;
108 int x;
109 int y;
110 #ifdef KBD_MODES
111 bool line_edit;
112 #endif
113 bool hangul;
114 unsigned short hlead, hvowel, htail;
117 static struct keyboard_parameters kbd_param[NB_SCREENS];
118 static bool kbd_loaded = false;
120 #ifdef KBD_MORSE_INPUT
121 /* FIXME: We should put this to a configuration file. */
122 static const char *morse_alphabets =
123 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
124 static const unsigned char morse_codes[] = {
125 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
126 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
127 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
128 0x73,0x55,0x4c,0x61,0x5a,0x80 };
130 static bool morse_mode = false;
131 #endif
133 /* Loads a custom keyboard into memory
134 call with NULL to reset keyboard */
135 int load_kbd(unsigned char* filename)
137 int fd, l;
138 int i = 0;
139 unsigned char buf[4];
141 if (filename == NULL)
143 kbd_loaded = false;
144 return 0;
147 fd = open_utf8(filename, O_RDONLY|O_BINARY);
148 if (fd < 0)
149 return 1;
151 while (read(fd, buf, 1) == 1 && i < KBD_BUF_SIZE)
153 /* check how many bytes to read for this character */
154 static const unsigned char sizes[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
155 size_t count;
157 for (count = 0; count < ARRAYLEN(sizes); count++)
159 if (buf[0] < sizes[count])
160 break;
163 if (count >= ARRAYLEN(sizes))
164 continue; /* Invalid size. */
166 if (read(fd, &buf[1], count) != (ssize_t)count)
168 close(fd);
169 kbd_loaded = false;
170 return 1;
173 FOR_NB_SCREENS(l)
174 utf8decode(buf, &kbd_param[l].kbd_buf[i]);
176 if (kbd_param[0].kbd_buf[i] != 0xFEFF &&
177 kbd_param[0].kbd_buf[i] != '\r') /*skip BOM & carriage returns */
179 i++;
183 close(fd);
184 kbd_loaded = true;
186 FOR_NB_SCREENS(l)
187 kbd_param[l].nchars = i;
189 return 0;
192 /* helper function to spell a char if voice UI is enabled */
193 static void kbd_spellchar(unsigned short c)
195 if (global_settings.talk_menu) /* voice UI? */
197 unsigned char tmp[5];
198 /* store char to pass to talk_spell */
199 unsigned char* utf8 = utf8encode(c, tmp);
200 *utf8 = 0;
202 if(c == ' ')
203 talk_id(VOICE_BLANK, false);
204 else
205 talk_spell(tmp, false);
209 #ifdef KBD_MODES
210 static void say_edit(void)
212 if(global_settings.talk_menu)
213 talk_id(VOICE_EDIT, false);
215 #endif
217 static void kbd_inschar(unsigned char* text, int buflen,
218 int* editpos, unsigned short ch)
220 int i, j, k, len;
221 unsigned char tmp[4];
222 unsigned char* utf8;
224 len = strlen(text);
225 k = utf8length(text);
226 utf8 = utf8encode(ch, tmp);
227 j = (long)utf8 - (long)tmp;
229 if (len + j < buflen)
231 for (i = len+j; k >= *editpos; i--)
233 text[i] = text[i-j];
234 if ((text[i] & MASK) != COMP)
235 k--;
238 while (j--)
239 text[i--] = tmp[j];
241 (*editpos)++;
245 static void kbd_delchar(unsigned char* text, int* editpos)
247 int i = 0;
248 unsigned char* utf8;
250 if (*editpos > 0)
252 utf8 = text + utf8seek(text, *editpos);
256 i++;
257 utf8--;
259 while ((*utf8 & MASK) == COMP);
261 while (utf8[i])
263 *utf8 = utf8[i];
264 utf8++;
267 *utf8 = 0;
268 (*editpos)--;
272 /* Lookup k value based on state of param (pm) */
273 static int get_param_k(const struct keyboard_parameters *pm)
275 return (pm->page*pm->lines + pm->y)*pm->max_chars + pm->x;
278 int kbd_input(char* text, int buflen)
280 bool done = false;
281 #ifdef CPU_ARM
282 /* This seems to keep the sizes for ARM way down */
283 struct keyboard_parameters * volatile param = kbd_param;
284 #else
285 struct keyboard_parameters * const param = kbd_param;
286 #endif
287 int l; /* screen loop variable */
288 int text_w = 0;
289 int editpos; /* Edit position on all screens */
290 const int statusbar_size = global_settings.statusbar
291 ? STATUSBAR_HEIGHT : 0;
292 unsigned short ch;
293 unsigned char *utf8;
294 bool cur_blink = true; /* Cursor on/off flag */
295 #ifdef KBD_MORSE_INPUT
296 bool morse_reading = false;
297 unsigned char morse_code = 0;
298 int morse_tick = 0;
299 char buf[2];
300 #endif
302 FOR_NB_SCREENS(l)
304 struct keyboard_parameters *pm = &param[l];
305 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96
306 struct screen *sc = &screens[l];
308 if (sc->getwidth() >= 160 && sc->getheight() >= 96)
310 pm->default_kbd =
311 "ABCDEFG abcdefg !?\" @#$%+'\n"
312 "HIJKLMN hijklmn 789 &_()-`\n"
313 "OPQRSTU opqrstu 456 §|{}/<\n"
314 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
315 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
316 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
317 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
318 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;";
320 pm->DEFAULT_LINES = 8;
322 else
323 #endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */
325 pm->default_kbd =
326 "ABCDEFG !?\" @#$%+'\n"
327 "HIJKLMN 789 &_()-`\n"
328 "OPQRSTU 456 §|{}/<\n"
329 "VWXYZ.,0123 ~=[]*>\n"
331 "abcdefg ¢£¤¥¦§©®¬\n"
332 "hijklmn «»°ºª¹²³¶\n"
333 "opqrstu ¯±×÷¡¿µ·¨\n"
334 "vwxyz., :;¼½¾ \n"
336 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
337 "àáâãäåæ ìíîï èéêë\n"
338 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
339 "òóôõöø çðþýÿ ùúûü";
341 pm->DEFAULT_LINES = 4;
345 char outline[256];
346 #ifdef HAVE_BUTTONBAR
347 struct gui_buttonbar buttonbar;
348 bool buttonbar_config = global_settings.buttonbar;
350 global_settings.buttonbar = true;
351 gui_buttonbar_init(&buttonbar);
353 FOR_NB_SCREENS(l)
354 gui_buttonbar_set_display(&buttonbar, &screens[l]);
355 #endif
357 FOR_NB_SCREENS(l)
359 struct keyboard_parameters *pm = &param[l];
361 if ( !kbd_loaded )
363 /* Copy default keyboard to buffer */
364 const unsigned char *p = pm->default_kbd;
365 int i = 0;
367 pm->curfont = FONT_SYSFIXED;
369 while (*p != 0)
370 p = utf8decode(p, &pm->kbd_buf[i++]);
372 pm->nchars = i;
374 else
376 pm->curfont = FONT_UI;
380 FOR_NB_SCREENS(l)
382 struct keyboard_parameters *pm = &param[l];
383 struct screen *sc = &screens[l];
384 int i, w;
386 pm->font = font_get(pm->curfont);
387 pm->font_h = pm->font->height;
389 /* check if FONT_UI fits the screen */
390 if (2*pm->font_h + 3 + statusbar_size +
391 BUTTONBAR_HEIGHT > sc->getheight())
393 pm->font = font_get(FONT_SYSFIXED);
394 pm->font_h = pm->font->height;
395 pm->curfont = FONT_SYSFIXED;
398 sc->setfont(pm->curfont);
399 pm->font_w = 0; /* reset font width */
400 /* find max width of keyboard glyphs */
401 for (i = 0; i < pm->nchars; i++)
403 w = font_get_width(pm->font, pm->kbd_buf[i]);
404 if ( w > pm->font_w )
405 pm->font_w = w;
408 /* Since we're going to be adding spaces, make sure that we check
409 * their width too */
410 w = font_get_width( pm->font, ' ' );
411 if ( w > pm->font_w )
412 pm->font_w = w;
415 FOR_NB_SCREENS(l)
417 struct keyboard_parameters *pm = &param[l];
418 struct screen *sc = &screens[l];
419 int i = 0;
421 /* Pad lines with spaces */
422 while (i < pm->nchars)
424 if (pm->kbd_buf[i] == '\n')
426 int k = sc->getwidth() / pm->font_w
427 - i % ( sc->getwidth() / pm->font_w ) - 1;
428 int j;
430 if (k == sc->getwidth() / pm->font_w - 1)
432 pm->nchars--;
434 for (j = i; j < pm->nchars; j++)
436 pm->kbd_buf[j] = pm->kbd_buf[j + 1];
439 else
441 if (pm->nchars + k - 1 >= KBD_BUF_SIZE)
442 { /* We don't want to overflow the buffer */
443 k = KBD_BUF_SIZE - pm->nchars;
446 for (j = pm->nchars + k - 1; j > i + k; j--)
448 pm->kbd_buf[j] = pm->kbd_buf[j-k];
451 pm->nchars += k;
452 k++;
454 while (k--)
456 pm->kbd_buf[i++] = ' ';
460 else
462 i++;
467 /* Find max width for text string */
468 utf8 = text;
469 FOR_NB_SCREENS(l)
471 struct keyboard_parameters *pm = &param[l];
472 struct screen *sc = &screens[l];
474 text_w = pm->font_w;
476 while (*utf8)
478 int w = font_get_width(pm->font, ch);
479 utf8 = (unsigned char*)utf8decode(utf8, &ch);
481 if (w > text_w)
482 text_w = w;
485 pm->max_chars_text = sc->getwidth() / text_w - 2;
487 /* Calculate keyboard grid size */
488 pm->max_chars = sc->getwidth() / pm->font_w;
490 if (!kbd_loaded)
492 pm->lines = pm->DEFAULT_LINES;
493 pm->keyboard_margin = DEFAULT_MARGIN;
495 else
497 pm->lines = (sc->getheight() - BUTTONBAR_HEIGHT - statusbar_size)
498 / pm->font_h - 1;
499 pm->keyboard_margin = sc->getheight() - BUTTONBAR_HEIGHT -
500 statusbar_size - (pm->lines+1)*pm->font_h;
502 if (pm->keyboard_margin < 3)
504 pm->lines--;
505 pm->keyboard_margin += pm->font_h;
508 if (pm->keyboard_margin > 6)
509 pm->keyboard_margin = 6;
512 pm->pages = (pm->nchars + (pm->lines*pm->max_chars-1))
513 / (pm->lines*pm->max_chars);
515 if (pm->pages == 1 && kbd_loaded)
516 pm->lines = (pm->nchars + pm->max_chars - 1) / pm->max_chars;
518 pm->main_y = pm->font_h*pm->lines + pm->keyboard_margin + statusbar_size;
519 pm->main_x = 0;
520 pm->keyboard_margin -= pm->keyboard_margin/2;
522 #ifdef KBD_MORSE_INPUT
523 pm->old_main_y = pm->main_y;
524 if (morse_mode)
525 pm->main_y = sc->getheight() - pm->font_h;
526 #endif
529 /* Initial edit position is after last character */
530 editpos = utf8length(text);
532 if (global_settings.talk_menu) /* voice UI? */
533 talk_spell(text, true); /* spell initial text */
536 while (!done)
538 /* These declarations are assigned to the screen on which the key
539 action occurred - pointers save a lot of space over array notation
540 when accessing the same array element countless times */
541 int button;
542 #if NB_SCREENS > 1
543 int button_screen;
544 #else
545 const int button_screen = 0;
546 #endif
547 struct keyboard_parameters *pm;
548 struct screen *sc;
550 int len_utf8 = utf8length(text);
552 FOR_NB_SCREENS(l)
553 screens[l].clear_display();
555 #ifdef KBD_MORSE_INPUT
556 if (morse_mode)
558 FOR_NB_SCREENS(l)
560 /* declare scoped pointers inside screen loops - hide the
561 declarations from previous block level */
562 const int w = 6; /* sysfixed font width */
563 struct keyboard_parameters *pm = &param[l];
564 struct screen *sc = &screens[l];
565 int i;
567 sc->setfont(FONT_SYSFIXED); /* Draw morse code screen with sysfont */
568 pm->x = 0;
569 pm->y = statusbar_size;
570 buf[1] = '\0';
572 /* Draw morse code table with code descriptions. */
573 for (i = 0; morse_alphabets[i] != '\0'; i++)
575 int morse_len;
576 int j;
578 buf[0] = morse_alphabets[i];
579 sc->putsxy(pm->x, pm->y, buf);
581 for (j = 0; (morse_codes[i] >> j) > 0x01; j++) ;
582 morse_len = j;
584 pm->x += w + 3;
585 for (j = 0; j < morse_len; j++)
587 if ((morse_codes[i] >> (morse_len-j-1)) & 0x01)
588 sc->fillrect(pm->x + j*4, pm->y + 2, 3, 4);
589 else
590 sc->fillrect(pm->x + j*4, pm->y + 3, 1, 2);
593 pm->x += w*5 - 3;
594 if (pm->x >= sc->getwidth() - w*6)
596 pm->x = 0;
597 pm->y += 8; /* sysfixed font height */
602 else
603 #endif /* KBD_MORSE_INPUT */
605 /* draw page */
606 FOR_NB_SCREENS(l)
608 struct keyboard_parameters *pm = &param[l];
609 struct screen *sc = &screens[l];
610 int i, j, k;
612 sc->setfont(pm->curfont);
614 k = pm->page*pm->max_chars*pm->lines;
616 for (i = j = 0; j < pm->lines && k < pm->nchars; k++)
618 int w;
619 utf8 = utf8encode(pm->kbd_buf[k], outline);
620 *utf8 = 0;
622 sc->getstringsize(outline, &w, NULL);
623 sc->putsxy(i*pm->font_w + (pm->font_w-w) / 2,
624 j*pm->font_h + statusbar_size, outline);
626 if (++i >= pm->max_chars)
628 i = 0;
629 j++;
635 /* separator */
636 FOR_NB_SCREENS(l)
638 struct keyboard_parameters *pm = &param[l];
639 struct screen *sc = &screens[l];
640 int i = 0, j = 0;
642 /* Clear text area one pixel above separator line so any overdraw
643 doesn't collide */
644 sc->set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID);
645 sc->fillrect(0, pm->main_y - pm->keyboard_margin - 1,
646 sc->getwidth(), pm->font_h + 4);
647 sc->set_drawmode(DRMODE_SOLID);
649 sc->hline(0, sc->getwidth() - 1, pm->main_y - pm->keyboard_margin);
651 /* write out the text */
652 sc->setfont(pm->curfont);
654 pm->curpos = MIN(editpos, pm->max_chars_text
655 - MIN(len_utf8 - editpos, 2));
656 pm->leftpos = editpos - pm->curpos;
657 utf8 = text + utf8seek(text, pm->leftpos);
659 text_w = pm->font_w;
661 while (*utf8 && i < pm->max_chars_text)
663 outline[j++] = *utf8++;
665 if ((*utf8 & MASK) != COMP)
667 int w;
668 outline[j] = 0;
669 j=0;
670 i++;
671 sc->getstringsize(outline, &w, NULL);
672 sc->putsxy(i*text_w + (text_w-w)/2, pm->main_y, outline);
676 if (pm->leftpos > 0)
678 /* Draw nicer bitmap arrow if room, else settle for "<". */
679 if (text_w >= 6 && pm->font_h >= 8)
681 screen_put_iconxy(sc, (text_w - 6) / 2,
682 pm->main_y + (pm->font_h - 8) / 2 ,
683 Icon_Reverse_Cursor);
685 else
687 int w;
688 sc->getstringsize("<", &w, NULL);
689 sc->putsxy(text_w - w, pm->main_y, "<");
693 if (len_utf8 - pm->leftpos > pm->max_chars_text)
695 /* Draw nicer bitmap arrow if room, else settle for ">". */
696 if (text_w >= 6 && pm->font_h >= 8)
698 screen_put_iconxy(sc, sc->getwidth() - text_w +
699 (text_w - 6) / 2,
700 pm->main_y + (pm->font_h - 8) / 2,
701 Icon_Cursor);
703 else
705 sc->putsxy(sc->getwidth() - text_w, pm->main_y, ">");
709 /* cursor */
710 i = (pm->curpos + 1) * text_w;
712 if (cur_blink)
713 sc->vline(i, pm->main_y, pm->main_y + pm->font_h - 1);
715 if (pm->hangul) /* draw underbar */
716 sc->hline(pm->curpos*text_w, (pm->curpos+1)*text_w,
717 pm->main_y + pm->font_h - 1);
720 cur_blink = !cur_blink;
722 #ifdef HAVE_BUTTONBAR
723 /* draw the button bar */
724 gui_buttonbar_set(&buttonbar, "Shift", "OK", "Del");
725 gui_buttonbar_draw(&buttonbar);
726 #endif
728 FOR_NB_SCREENS(l)
730 struct keyboard_parameters *pm = &param[l];
731 struct screen *sc = &screens[l];
733 sc->set_drawmode(DRMODE_COMPLEMENT);
734 #ifdef KBD_MODES
735 if (pm->line_edit)
736 sc->fillrect(0, pm->main_y - pm->keyboard_margin + 2,
737 sc->getwidth(), pm->font_h + 2);
738 else /* highlight the key that has focus */
739 #endif
740 sc->fillrect(pm->font_w*pm->x,
741 statusbar_size + pm->font_h*pm->y,
742 pm->font_w, pm->font_h);
743 sc->set_drawmode(DRMODE_SOLID);
746 gui_syncstatusbar_draw(&statusbars, true);
747 FOR_NB_SCREENS(l)
748 screens[l].update();
750 button = get_action(CONTEXT_KEYBOARD, HZ/2);
751 #if NB_SCREENS > 1
752 button_screen = (get_action_statuscode(NULL) & ACTION_REMOTE) ? 1 : 0;
753 #endif
754 pm = &param[button_screen];
755 sc = &screens[button_screen];
757 #if defined KBD_MORSE_INPUT && !defined KBD_MODES
758 if (morse_mode)
760 /* Remap some buttons for morse mode. */
761 if (button == ACTION_KBD_LEFT)
762 button = ACTION_KBD_CURSOR_LEFT;
763 if (button == ACTION_KBD_RIGHT)
764 button = ACTION_KBD_CURSOR_RIGHT;
766 #endif
768 switch ( button )
770 case ACTION_KBD_ABORT:
771 FOR_NB_SCREENS(l)
772 screens[l].setfont(FONT_UI);
774 #ifdef HAVE_BUTTONBAR
775 global_settings.buttonbar=buttonbar_config;
776 #endif
777 return -1;
778 break;
780 case ACTION_KBD_PAGE_FLIP:
782 int k;
783 #ifdef KBD_MORSE_INPUT
784 if (morse_mode)
785 break;
786 #endif
787 if (++pm->page >= pm->pages)
788 pm->page = 0;
790 k = get_param_k(pm);
791 kbd_spellchar(pm->kbd_buf[k]);
792 break;
795 #ifdef KBD_MORSE_INPUT
796 case ACTION_KBD_MORSE_INPUT:
797 morse_mode = !morse_mode;
799 FOR_NB_SCREENS(l)
801 struct keyboard_parameters *pm = &param[l];
802 struct screen *sc = &screens[l];
804 pm->x = pm->y = pm->page = 0;
806 if (morse_mode)
808 pm->old_main_y = pm->main_y;
809 pm->main_y = sc->getheight() - pm->font_h;
811 else
813 pm->main_y = pm->old_main_y;
816 /* FIXME: We should talk something like Morse mode.. */
817 break;
818 #endif /* KBD_MORSE_INPUT */
820 case ACTION_KBD_RIGHT:
821 #ifdef KBD_MODES
822 #ifdef KBD_MORSE_INPUT
823 /* allow cursor change in non line edit morse mode */
824 if (pm->line_edit || morse_mode)
825 #else
826 /* right doubles as cursor_right in line_edit */
827 if (pm->line_edit)
828 #endif
830 pm->hangul = false;
832 if (editpos < len_utf8)
834 int c = utf8seek(text, ++editpos);
835 kbd_spellchar(text[c]);
837 #if CONFIG_CODEC == SWCODEC
838 else if (global_settings.talk_menu)
839 pcmbuf_beep(1000, 150, 1500);
840 #endif
842 else
843 #endif /* KBD_MODES */
845 int k;
846 #ifdef KBD_MORSE_INPUT
847 if (morse_mode)
848 break;
849 #endif
850 if (++pm->x >= pm->max_chars)
852 #ifndef KBD_PAGE_FLIP
853 /* no dedicated flip key - flip page on wrap */
854 if (++pm->page >= pm->pages)
855 pm->page = 0;
856 #endif
857 pm->x = 0;
860 k = get_param_k(pm);
861 kbd_spellchar(pm->kbd_buf[k]);
863 break;
865 case ACTION_KBD_LEFT:
866 #ifdef KBD_MODES
867 #ifdef KBD_MORSE_INPUT
868 /* allow cursor change in non line edit morse mode */
869 if (pm->line_edit || morse_mode)
870 #else
871 /* left doubles as cursor_left in line_edit */
872 if (pm->line_edit)
873 #endif
875 pm->hangul = false;
877 if (editpos > 0)
879 int c = utf8seek(text, --editpos);
880 kbd_spellchar(text[c]);
882 #if CONFIG_CODEC == SWCODEC
883 else if (global_settings.talk_menu)
884 pcmbuf_beep(1000, 150, 1500);
885 #endif
887 else
888 #endif /* KBD_MODES */
890 int k;
891 #ifdef KBD_MORSE_INPUT
892 if (morse_mode)
893 break;
894 #endif
895 if (--pm->x < 0)
897 #ifndef KBD_PAGE_FLIP
898 /* no dedicated flip key - flip page on wrap */
899 if (--pm->page < 0)
900 pm->page = pm->pages - 1;
901 #endif
902 pm->x = pm->max_chars - 1;
905 k = get_param_k(pm);
906 kbd_spellchar(pm->kbd_buf[k]);
908 break;
910 case ACTION_KBD_DOWN:
911 #ifdef KBD_MORSE_INPUT
912 #ifdef KBD_MODES
913 if (morse_mode)
915 pm->line_edit = !pm->line_edit;
916 if(pm->line_edit)
917 say_edit();
919 else
920 #else
921 if (morse_mode)
922 break;
923 #endif
924 #endif /* KBD_MORSE_INPUT */
926 #ifdef KBD_MODES
927 if (pm->line_edit)
929 pm->y = 0;
930 pm->line_edit = false;
932 else
933 #endif
934 if (++pm->y >= pm->lines)
935 #ifdef KBD_MODES
937 pm->line_edit = true;
938 say_edit();
940 #else
941 pm->y = 0;
942 #endif
944 #ifdef KBD_MODES
945 if (!pm->line_edit)
946 #endif
948 int k = get_param_k(pm);
949 kbd_spellchar(pm->kbd_buf[k]);
951 break;
953 case ACTION_KBD_UP:
954 #ifdef KBD_MORSE_INPUT
955 #ifdef KBD_MODES
956 if (morse_mode)
958 pm->line_edit = !pm->line_edit;
959 if(pm->line_edit)
960 say_edit();
962 else
963 #else
964 if (morse_mode)
965 break;
966 #endif
967 #endif /* KBD_MORSE_INPUT */
969 #ifdef KBD_MODES
970 if (pm->line_edit)
972 pm->y = pm->lines - 1;
973 pm->line_edit = false;
975 else
976 #endif
977 if (--pm->y < 0)
978 #ifdef KBD_MODES
980 pm->line_edit = true;
981 say_edit();
983 #else
984 pm->y = pm->lines - 1;
985 #endif
987 #ifdef KBD_MODES
988 if (!pm->line_edit)
989 #endif
991 int k = get_param_k(pm);
992 kbd_spellchar(pm->kbd_buf[k]);
994 break;
996 case ACTION_KBD_DONE:
997 /* accepts what was entered and continues */
998 done = true;
999 break;
1001 #ifdef KBD_MORSE_INPUT
1002 case ACTION_KBD_MORSE_SELECT:
1003 if (morse_mode && morse_reading)
1005 morse_code <<= 1;
1006 if ((current_tick - morse_tick) > HZ/5)
1007 morse_code |= 0x01;
1010 break;
1011 #endif /* KBD_MORSE_INPUT */
1013 case ACTION_KBD_SELECT:
1014 case ACTION_KBD_SELECT_REM:
1015 #ifdef KBD_MORSE_INPUT
1016 #ifdef KBD_MODES
1017 if (morse_mode && !pm->line_edit)
1018 #else
1019 if (morse_mode)
1020 #endif
1022 morse_tick = current_tick;
1024 if (!morse_reading)
1026 morse_reading = true;
1027 morse_code = 1;
1029 break;
1031 #endif /* KBD_MORSE_INPUT */
1033 /* inserts the selected char */
1034 #ifdef KBD_MODES
1035 if (pm->line_edit)
1036 { /* select doubles as backspace in line_edit */
1037 if (pm->hangul)
1039 if (pm->htail)
1040 pm->htail = 0;
1041 else if (pm->hvowel)
1042 pm->hvowel = 0;
1043 else
1044 pm->hangul = false;
1047 kbd_delchar(text, &editpos);
1049 if (pm->hangul)
1051 if (pm->hvowel)
1052 ch = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1053 else
1054 ch = pm->hlead;
1055 kbd_inschar(text, buflen, &editpos, ch);
1058 else
1059 #endif /* KBD_MODES */
1061 /* find input char */
1062 int k = get_param_k(pm);
1063 ch = (k < pm->nchars) ? pm->kbd_buf[k] : ' ';
1065 /* check for hangul input */
1066 if (ch >= 0x3131 && ch <= 0x3163)
1068 unsigned short tmp;
1070 if (!pm->hangul)
1072 pm->hlead = pm->hvowel = pm->htail = 0;
1073 pm->hangul = true;
1076 if (!pm->hvowel)
1078 pm->hvowel = ch;
1080 else if (!pm->htail)
1082 pm->htail = ch;
1084 else
1085 { /* previous hangul complete */
1086 /* check whether tail is actually lead of next char */
1087 tmp = hangul_join(pm->htail, ch, 0);
1089 if (tmp != 0xfffd)
1091 tmp = hangul_join(pm->hlead, pm->hvowel, 0);
1092 kbd_delchar(text, &editpos);
1093 kbd_inschar(text, buflen, &editpos, tmp);
1094 /* insert dummy char */
1095 kbd_inschar(text, buflen, &editpos, ' ');
1096 pm->hlead = pm->htail;
1097 pm->hvowel = ch;
1098 pm->htail = 0;
1100 else
1102 pm->hvowel = pm->htail = 0;
1103 pm->hlead = ch;
1107 /* combine into hangul */
1108 tmp = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1110 if (tmp != 0xfffd)
1112 kbd_delchar(text, &editpos);
1113 ch = tmp;
1115 else
1117 pm->hvowel = pm->htail = 0;
1118 pm->hlead = ch;
1121 else
1123 pm->hangul = false;
1126 /* insert char */
1127 kbd_inschar(text, buflen, &editpos, ch);
1130 if (global_settings.talk_menu) /* voice UI? */
1131 talk_spell(text, false);
1133 /* speak revised text */
1134 break;
1136 #if !defined (KBD_MODES) || defined (KBD_CURSOR_KEYS)
1137 case ACTION_KBD_BACKSPACE:
1138 if (pm->hangul)
1140 if (pm->htail)
1141 pm->htail = 0;
1142 else if (pm->hvowel)
1143 pm->hvowel = 0;
1144 else
1145 pm->hangul = false;
1148 kbd_delchar(text, &editpos);
1150 if (pm->hangul)
1152 if (pm->hvowel)
1153 ch = hangul_join(pm->hlead, pm->hvowel, pm->htail);
1154 else
1155 ch = pm->hlead;
1156 kbd_inschar(text, buflen, &editpos, ch);
1159 if (global_settings.talk_menu) /* voice UI? */
1160 talk_spell(text, false); /* speak revised text */
1161 break;
1163 case ACTION_KBD_CURSOR_RIGHT:
1164 pm->hangul = false;
1166 if (editpos < len_utf8)
1168 int c = utf8seek(text, ++editpos);
1169 kbd_spellchar(text[c]);
1171 #if CONFIG_CODEC == SWCODEC
1172 else if (global_settings.talk_menu)
1173 pcmbuf_beep(1000, 150, 1500);
1174 #endif
1175 break;
1177 case ACTION_KBD_CURSOR_LEFT:
1178 pm->hangul = false;
1180 if (editpos > 0)
1182 int c = utf8seek(text, --editpos);
1183 kbd_spellchar(text[c]);
1185 #if CONFIG_CODEC == SWCODEC
1186 else if (global_settings.talk_menu)
1187 pcmbuf_beep(1000, 150, 1500);
1188 #endif
1189 break;
1190 #endif /* !defined (KBD_MODES) || defined (KBD_CURSOR_KEYS) */
1192 case BUTTON_NONE:
1193 gui_syncstatusbar_draw(&statusbars, false);
1194 #ifdef KBD_MORSE_INPUT
1195 if (morse_reading)
1197 int j;
1198 logf("Morse: 0x%02x", morse_code);
1199 morse_reading = false;
1201 for (j = 0; morse_alphabets[j] != '\0'; j++)
1203 if (morse_codes[j] == morse_code)
1204 break ;
1207 if (morse_alphabets[j] == '\0')
1209 logf("Morse code not found");
1210 break ;
1213 /* turn off hangul input */
1214 FOR_NB_SCREENS(l)
1215 param[l].hangul = false;
1216 kbd_inschar(text, buflen, &editpos, morse_alphabets[j]);
1218 if (global_settings.talk_menu) /* voice UI? */
1219 talk_spell(text, false); /* speak revised text */
1221 #endif /* KBD_MORSE_INPUT */
1222 break;
1224 default:
1225 if (default_event_handler(button) == SYS_USB_CONNECTED)
1227 FOR_NB_SCREENS(l)
1228 screens[l].setfont(FONT_SYSFIXED);
1230 break;
1232 } /* end switch */
1234 if (button != BUTTON_NONE)
1236 cur_blink = true;
1240 #ifdef HAVE_BUTTONBAR
1241 global_settings.buttonbar = buttonbar_config;
1242 #endif
1244 FOR_NB_SCREENS(l)
1245 screens[l].setfont(FONT_UI);
1247 return 0;