Update Beast installation instructions to use beastpatcher and remove instructions...
[kugel-rb.git] / apps / recorder / keyboard.c
bloba30871015bc24e3802790f1551a59b7c385b1d64
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"
40 #include "viewport.h"
42 #ifndef O_BINARY
43 #define O_BINARY 0
44 #endif
47 #define DEFAULT_MARGIN 6
48 #define KBD_BUF_SIZE 500
50 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
51 (CONFIG_KEYPAD == IRIVER_H300_PAD)
52 #define KBD_CURSOR_KEYS /* certain key combos move the cursor even if not
53 in line edit mode */
54 #define KBD_MODES /* I-Rivers can use picker, line edit and cursor keys */
55 #define KBD_MORSE_INPUT /* I-Rivers have a Morse input mode */
57 #elif CONFIG_KEYPAD == ONDIO_PAD /* restricted Ondio keypad */
58 #define KBD_MODES /* Ondio uses 2 modes, picker and line edit */
60 #elif (CONFIG_KEYPAD == IPOD_1G2G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) \
61 || (CONFIG_KEYPAD == IPOD_4G_PAD)
62 #define KBD_MODES /* iPod uses 2 modes, picker and line edit */
63 #define KBD_MORSE_INPUT
65 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
66 #define KBD_MODES /* iFP7xx uses 2 modes, picker and line edit */
68 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) || (CONFIG_KEYPAD == IAUDIO_M3_PAD)
69 #define KBD_MODES /* iAudios use 2 modes, picker and line edit */
71 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
72 #define KBD_MODES /* iriver H10 uses 2 modes, picker and line edit */
73 #define KBD_MORSE_INPUT
75 #elif CONFIG_KEYPAD == GIGABEAT_PAD
76 #define KBD_CURSOR_KEYS
77 #define KBD_MODES
78 #define KBD_MORSE_INPUT
80 #elif CONFIG_KEYPAD == SANSA_E200_PAD
81 #define KBD_CURSOR_KEYS
82 #define KBD_MODES
84 #elif CONFIG_KEYPAD == MROBE100_PAD
85 #define KBD_MORSE_INPUT
86 #endif
88 struct keyboard_parameters
90 const unsigned char* default_kbd;
91 int DEFAULT_LINES;
92 unsigned short kbd_buf[KBD_BUF_SIZE];
93 int nchars;
94 int font_w;
95 int font_h;
96 struct font* font;
97 int curfont;
98 int main_x;
99 int main_y;
100 int max_chars;
101 int max_chars_text;
102 int lines;
103 int pages;
104 int keyboard_margin;
105 int old_main_y;
106 int curpos;
107 int leftpos;
108 int page;
109 int x;
110 int y;
111 #ifdef KBD_MODES
112 bool line_edit;
113 #endif
114 bool hangul;
115 unsigned short hlead, hvowel, htail;
118 static struct keyboard_parameters kbd_param[NB_SCREENS];
119 static bool kbd_loaded = false;
121 #ifdef KBD_MORSE_INPUT
122 /* FIXME: We should put this to a configuration file. */
123 static const char *morse_alphabets =
124 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
125 static const unsigned char morse_codes[] = {
126 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
127 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
128 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
129 0x73,0x55,0x4c,0x61,0x5a,0x80 };
131 static bool morse_mode = false;
132 #endif
134 /* Loads a custom keyboard into memory
135 call with NULL to reset keyboard */
136 int load_kbd(unsigned char* filename)
138 int fd, l;
139 int i = 0;
140 unsigned char buf[4];
142 if (filename == NULL)
144 kbd_loaded = false;
145 return 0;
148 fd = open_utf8(filename, O_RDONLY|O_BINARY);
149 if (fd < 0)
150 return 1;
152 while (read(fd, buf, 1) == 1 && i < KBD_BUF_SIZE)
154 /* check how many bytes to read for this character */
155 static const unsigned char sizes[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
156 size_t count;
158 for (count = 0; count < ARRAYLEN(sizes); count++)
160 if (buf[0] < sizes[count])
161 break;
164 if (count >= ARRAYLEN(sizes))
165 continue; /* Invalid size. */
167 if (read(fd, &buf[1], count) != (ssize_t)count)
169 close(fd);
170 kbd_loaded = false;
171 return 1;
174 FOR_NB_SCREENS(l)
175 utf8decode(buf, &kbd_param[l].kbd_buf[i]);
177 if (kbd_param[0].kbd_buf[i] != 0xFEFF &&
178 kbd_param[0].kbd_buf[i] != '\r') /*skip BOM & carriage returns */
180 i++;
184 close(fd);
185 kbd_loaded = true;
187 FOR_NB_SCREENS(l)
188 kbd_param[l].nchars = i;
190 return 0;
193 /* helper function to spell a char if voice UI is enabled */
194 static void kbd_spellchar(unsigned short c)
196 if (global_settings.talk_menu) /* voice UI? */
198 unsigned char tmp[5];
199 /* store char to pass to talk_spell */
200 unsigned char* utf8 = utf8encode(c, tmp);
201 *utf8 = 0;
203 if(c == ' ')
204 talk_id(VOICE_BLANK, false);
205 else
206 talk_spell(tmp, false);
210 #ifdef KBD_MODES
211 static void say_edit(void)
213 if(global_settings.talk_menu)
214 talk_id(VOICE_EDIT, false);
216 #endif
218 static void kbd_inschar(unsigned char* text, int buflen,
219 int* editpos, unsigned short ch)
221 int i, j, k, len;
222 unsigned char tmp[4];
223 unsigned char* utf8;
225 len = strlen(text);
226 k = utf8length(text);
227 utf8 = utf8encode(ch, tmp);
228 j = (long)utf8 - (long)tmp;
230 if (len + j < buflen)
232 for (i = len+j; k >= *editpos; i--)
234 text[i] = text[i-j];
235 if ((text[i] & MASK) != COMP)
236 k--;
239 while (j--)
240 text[i--] = tmp[j];
242 (*editpos)++;
246 static void kbd_delchar(unsigned char* text, int* editpos)
248 int i = 0;
249 unsigned char* utf8;
251 if (*editpos > 0)
253 utf8 = text + utf8seek(text, *editpos);
257 i++;
258 utf8--;
260 while ((*utf8 & MASK) == COMP);
262 while (utf8[i])
264 *utf8 = utf8[i];
265 utf8++;
268 *utf8 = 0;
269 (*editpos)--;
273 /* Lookup k value based on state of param (pm) */
274 static int get_param_k(const struct keyboard_parameters *pm)
276 return (pm->page*pm->lines + pm->y)*pm->max_chars + pm->x;
279 int kbd_input(char* text, int buflen)
281 bool done = false;
282 #ifdef CPU_ARM
283 /* This seems to keep the sizes for ARM way down */
284 struct keyboard_parameters * volatile param = kbd_param;
285 #else
286 struct keyboard_parameters * const param = kbd_param;
287 #endif
288 int l; /* screen loop variable */
289 int text_w = 0;
290 int editpos; /* Edit position on all screens */
291 const int statusbar_size = 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
301 int oldbars = viewportmanager_set_statusbar(VP_SB_HIDE_ALL);
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 FOR_NB_SCREENS(l)
747 screens[l].update();
749 button = get_action(CONTEXT_KEYBOARD, HZ/2);
750 #if NB_SCREENS > 1
751 button_screen = (get_action_statuscode(NULL) & ACTION_REMOTE) ? 1 : 0;
752 #endif
753 pm = &param[button_screen];
754 sc = &screens[button_screen];
756 #if defined KBD_MORSE_INPUT && !defined KBD_MODES
757 if (morse_mode)
759 /* Remap some buttons for morse mode. */
760 if (button == ACTION_KBD_LEFT)
761 button = ACTION_KBD_CURSOR_LEFT;
762 if (button == ACTION_KBD_RIGHT)
763 button = ACTION_KBD_CURSOR_RIGHT;
765 #endif
767 switch ( button )
769 case ACTION_KBD_ABORT:
770 FOR_NB_SCREENS(l)
771 screens[l].setfont(FONT_UI);
773 #ifdef HAVE_BUTTONBAR
774 global_settings.buttonbar=buttonbar_config;
775 #endif
776 viewportmanager_set_statusbar(oldbars);
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 #ifdef KBD_MORSE_INPUT
1194 if (morse_reading)
1196 int j;
1197 logf("Morse: 0x%02x", morse_code);
1198 morse_reading = false;
1200 for (j = 0; morse_alphabets[j] != '\0'; j++)
1202 if (morse_codes[j] == morse_code)
1203 break ;
1206 if (morse_alphabets[j] == '\0')
1208 logf("Morse code not found");
1209 break ;
1212 /* turn off hangul input */
1213 FOR_NB_SCREENS(l)
1214 param[l].hangul = false;
1215 kbd_inschar(text, buflen, &editpos, morse_alphabets[j]);
1217 if (global_settings.talk_menu) /* voice UI? */
1218 talk_spell(text, false); /* speak revised text */
1220 #endif /* KBD_MORSE_INPUT */
1221 break;
1223 default:
1224 if (default_event_handler(button) == SYS_USB_CONNECTED)
1226 FOR_NB_SCREENS(l)
1227 screens[l].setfont(FONT_SYSFIXED);
1229 break;
1231 } /* end switch */
1233 if (button != BUTTON_NONE)
1235 cur_blink = true;
1239 #ifdef HAVE_BUTTONBAR
1240 global_settings.buttonbar = buttonbar_config;
1241 #endif
1243 FOR_NB_SCREENS(l)
1244 screens[l].setfont(FONT_UI);
1245 viewportmanager_set_statusbar(oldbars);
1247 return 0;