1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
30 #include "rbunicode.h"
31 #include "buttonbar.h"
42 #include "appevents.h"
49 #define DEFAULT_MARGIN 6
50 #define KBD_BUF_SIZE 500
52 #if (CONFIG_KEYPAD == ONDIO_PAD) \
53 || (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
54 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
55 || (CONFIG_KEYPAD == IPOD_4G_PAD) \
56 || (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD) \
57 || (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) \
58 || (CONFIG_KEYPAD == IAUDIO_M3_PAD) \
59 || (CONFIG_KEYPAD == IRIVER_H10_PAD)
60 /* no key combos to move the cursor if not in line edit mode */
61 #define KBD_MODES /* uses 2 modes, picker and line edit */
63 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) \
64 || (CONFIG_KEYPAD == IRIVER_H300_PAD) \
65 || (CONFIG_KEYPAD == GIGABEAT_PAD) \
66 || (CONFIG_KEYPAD == GIGABEAT_S_PAD) \
67 || (CONFIG_KEYPAD == SANSA_E200_PAD) \
68 || (CONFIG_KEYPAD == SANSA_FUZE_PAD) \
69 || (CONFIG_KEYPAD == SANSA_C200_PAD) \
70 || (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
71 /* certain key combos move the cursor even if not in line edit mode */
72 #define KBD_CURSOR_KEYS
73 #define KBD_MODES /* uses 2 modes, picker and line edit */
76 #define KBD_CURSOR_KEYS /* certain keys move the cursor, no line edit mode */
79 #if (CONFIG_KEYPAD == IRIVER_H100_PAD) \
80 || (CONFIG_KEYPAD == IRIVER_H300_PAD) \
81 || (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
82 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
83 || (CONFIG_KEYPAD == IPOD_4G_PAD) \
84 || (CONFIG_KEYPAD == IRIVER_H10_PAD) \
85 || (CONFIG_KEYPAD == GIGABEAT_PAD) \
86 || (CONFIG_KEYPAD == GIGABEAT_S_PAD) \
87 || (CONFIG_KEYPAD == MROBE100_PAD) \
88 || (CONFIG_KEYPAD == SANSA_E200_PAD) \
89 || (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) \
90 || (CONFIG_KEYPAD == PHILIPS_SA9200_PAD)
91 /* certain key combos toggle input mode between keyboard input and Morse input */
92 #define KBD_TOGGLE_INPUT
95 struct keyboard_parameters
97 const unsigned char* default_kbd
;
99 unsigned short kbd_buf
[KBD_BUF_SIZE
];
122 unsigned short hlead
, hvowel
, htail
;
125 static struct keyboard_parameters kbd_param
[NB_SCREENS
];
126 static bool kbd_loaded
= false;
128 #ifdef HAVE_MORSE_INPUT
129 /* FIXME: We should put this to a configuration file. */
130 static const char *morse_alphabets
=
131 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
132 static const unsigned char morse_codes
[] = {
133 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
134 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
135 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
136 0x73,0x55,0x4c,0x61,0x5a,0x80 };
140 /* Loads a custom keyboard into memory
141 call with NULL to reset keyboard */
142 int load_kbd(unsigned char* filename
)
146 unsigned char buf
[4];
150 struct keyboard_parameters
*pm
= &kbd_param
[l
];
151 pm
->x
= pm
->y
= pm
->page
= 0;
154 if (filename
== NULL
)
160 fd
= open_utf8(filename
, O_RDONLY
|O_BINARY
);
164 while (read(fd
, buf
, 1) == 1 && i
< KBD_BUF_SIZE
)
166 /* check how many bytes to read for this character */
167 static const unsigned char sizes
[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
171 for (count
= 0; count
< ARRAYLEN(sizes
); count
++)
173 if (buf
[0] < sizes
[count
])
177 if (count
>= ARRAYLEN(sizes
))
178 continue; /* Invalid size. */
180 if (read(fd
, &buf
[1], count
) != (ssize_t
)count
)
187 utf8decode(buf
, &ch
);
189 kbd_param
[l
].kbd_buf
[i
] = ch
;
191 if (ch
!= 0xFEFF && ch
!= '\r') /*skip BOM & carriage returns */
199 kbd_param
[l
].nchars
= i
;
204 /* helper function to spell a char if voice UI is enabled */
205 static void kbd_spellchar(unsigned short c
)
207 if (global_settings
.talk_menu
) /* voice UI? */
209 unsigned char tmp
[5];
210 /* store char to pass to talk_spell */
211 unsigned char* utf8
= utf8encode(c
, tmp
);
215 talk_id(VOICE_BLANK
, false);
217 talk_spell(tmp
, false);
222 static void say_edit(void)
224 if(global_settings
.talk_menu
)
225 talk_id(VOICE_EDIT
, false);
229 static void kbd_inschar(unsigned char* text
, int buflen
,
230 int* editpos
, unsigned short ch
)
233 unsigned char tmp
[4];
237 utf8
= utf8encode(ch
, tmp
);
238 j
= (long)utf8
- (long)tmp
;
240 if (len
+ j
< buflen
)
242 i
= utf8seek(text
, *editpos
);
244 memmove(utf8
+ j
, utf8
, len
- i
+ 1);
245 memcpy(utf8
, tmp
, j
);
250 static void kbd_delchar(unsigned char* text
, int* editpos
)
259 i
= utf8seek(text
, *editpos
);
261 j
= utf8seek(utf8
, 1);
262 memmove(utf8
, utf8
+ j
, len
- i
- j
+ 1);
266 /* Lookup k value based on state of param (pm) */
267 static unsigned short get_kbd_ch(const struct keyboard_parameters
*pm
)
269 int k
= (pm
->page
*pm
->lines
+ pm
->y
)*pm
->max_chars
+ pm
->x
;
270 return (k
< pm
->nchars
)? pm
->kbd_buf
[k
]: ' ';
273 int kbd_input(char* text
, int buflen
)
277 /* This seems to keep the sizes for ARM way down */
278 struct keyboard_parameters
* volatile param
= kbd_param
;
280 struct keyboard_parameters
* const param
= kbd_param
;
282 int l
; /* screen loop variable */
283 int editpos
; /* Edit position on all screens */
286 bool cur_blink
= true; /* Cursor on/off flag */
287 int ret
= 0; /* assume success */
288 #ifdef HAVE_MORSE_INPUT
289 bool morse_mode
= global_settings
.morse_input
;
290 bool morse_reading
= false;
291 unsigned char morse_code
= 0;
296 struct keyboard_parameters
*pm
= ¶m
[l
];
297 viewportmanager_theme_enable(l
, false, NULL
);
298 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96
299 struct screen
*sc
= &screens
[l
];
301 if (sc
->getwidth() >= 160 && sc
->getheight() >= 96)
304 "ABCDEFG abcdefg !?\" @#$%+'\n"
305 "HIJKLMN hijklmn 789 &_()-`\n"
306 "OPQRSTU opqrstu 456 §|{}/<\n"
307 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
308 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
309 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
310 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
311 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;";
313 pm
->DEFAULT_LINES
= 8;
316 #endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */
319 "ABCDEFG !?\" @#$%+'\n"
320 "HIJKLMN 789 &_()-`\n"
321 "OPQRSTU 456 §|{}/<\n"
322 "VWXYZ.,0123 ~=[]*>\n"
324 "abcdefg ¢£¤¥¦§©®¬\n"
325 "hijklmn «»°ºª¹²³¶\n"
326 "opqrstu ¯±×÷¡¿µ·¨\n"
329 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
330 "àáâãäåæ ìíîï èéêë\n"
331 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
334 pm
->DEFAULT_LINES
= 4;
339 #ifdef HAVE_BUTTONBAR
340 struct gui_buttonbar buttonbar
;
341 bool buttonbar_config
= global_settings
.buttonbar
;
343 global_settings
.buttonbar
= true;
344 gui_buttonbar_init(&buttonbar
);
347 gui_buttonbar_set_display(&buttonbar
, &screens
[l
]);
352 struct keyboard_parameters
*pm
= ¶m
[l
];
356 /* Copy default keyboard to buffer */
357 const unsigned char *p
= pm
->default_kbd
;
360 pm
->curfont
= FONT_SYSFIXED
;
363 p
= utf8decode(p
, &pm
->kbd_buf
[i
++]);
369 pm
->curfont
= FONT_UI
;
375 struct keyboard_parameters
*pm
= ¶m
[l
];
376 struct screen
*sc
= &screens
[l
];
379 pm
->font
= font_get(pm
->curfont
);
380 pm
->font_h
= pm
->font
->height
;
382 /* check if FONT_UI fits the screen */
383 if (2*pm
->font_h
+ 3 + BUTTONBAR_HEIGHT
> sc
->getheight())
385 pm
->font
= font_get(FONT_SYSFIXED
);
386 pm
->font_h
= pm
->font
->height
;
387 pm
->curfont
= FONT_SYSFIXED
;
390 /* find max width of keyboard glyphs.
391 * since we're going to be adding spaces,
392 * max width is at least their width */
393 pm
->font_w
= font_get_width(pm
->font
, ' ');
394 for (i
= 0; i
< pm
->nchars
; i
++)
396 if (pm
->kbd_buf
[i
] != '\n')
398 w
= font_get_width(pm
->font
, pm
->kbd_buf
[i
]);
407 struct keyboard_parameters
*pm
= ¶m
[l
];
408 struct screen
*sc
= &screens
[l
];
411 pm
->max_chars
= sc
->getwidth() / pm
->font_w
;
413 /* Pad lines with spaces */
414 while (i
< pm
->nchars
)
416 if (pm
->kbd_buf
[i
] == '\n')
418 int k
= pm
->max_chars
- i
% ( pm
->max_chars
) - 1;
421 if (k
== pm
->max_chars
- 1)
425 for (j
= i
; j
< pm
->nchars
; j
++)
427 pm
->kbd_buf
[j
] = pm
->kbd_buf
[j
+ 1];
432 if (pm
->nchars
+ k
- 1 >= KBD_BUF_SIZE
)
433 { /* We don't want to overflow the buffer */
434 k
= KBD_BUF_SIZE
- pm
->nchars
;
437 for (j
= pm
->nchars
+ k
- 1; j
> i
+ k
; j
--)
439 pm
->kbd_buf
[j
] = pm
->kbd_buf
[j
-k
];
447 pm
->kbd_buf
[i
++] = ' ';
458 /* Find max width for text string */
461 struct keyboard_parameters
*pm
= ¶m
[l
];
462 struct screen
*sc
= &screens
[l
];
463 int icon_w
, sc_w
, sc_h
;
465 pm
->text_w
= pm
->font_w
;
471 utf8
= (unsigned char*)utf8decode(utf8
, &ch
);
472 w
= font_get_width(pm
->font
, ch
);
477 icon_w
= get_icon_width(l
);
478 sc_w
= sc
->getwidth();
479 sc_h
= sc
->getheight();
480 pm
->max_chars_text
= (sc_w
- icon_w
* 2 - 2) / pm
->text_w
;
481 if(pm
->max_chars_text
< 3 && icon_w
> pm
->text_w
)
482 pm
->max_chars_text
= sc_w
/ pm
->text_w
- 2;
484 pm
->lines
= (sc_h
- BUTTONBAR_HEIGHT
) / pm
->font_h
- 1;
486 if (!kbd_loaded
&& pm
->lines
> pm
->DEFAULT_LINES
)
487 pm
->lines
= pm
->DEFAULT_LINES
;
489 pm
->keyboard_margin
= sc_h
- BUTTONBAR_HEIGHT
490 - (pm
->lines
+1)*pm
->font_h
;
492 if (pm
->keyboard_margin
< 3 && pm
->lines
> 1)
495 pm
->keyboard_margin
+= pm
->font_h
;
498 if (pm
->keyboard_margin
> DEFAULT_MARGIN
)
499 pm
->keyboard_margin
= DEFAULT_MARGIN
;
501 pm
->pages
= (pm
->nchars
+ (pm
->lines
*pm
->max_chars
-1))
502 / (pm
->lines
*pm
->max_chars
);
505 pm
->lines
= (pm
->nchars
+ pm
->max_chars
- 1) / pm
->max_chars
;
507 pm
->main_y
= pm
->font_h
*pm
->lines
+ pm
->keyboard_margin
;
508 pm
->keyboard_margin
-= pm
->keyboard_margin
/2;
510 #ifdef HAVE_MORSE_INPUT
511 pm
->old_main_y
= pm
->main_y
;
513 pm
->main_y
= sc_h
- pm
->font_h
- BUTTONBAR_HEIGHT
;
517 /* Initial edit position is after last character */
518 editpos
= utf8length(text
);
520 if (global_settings
.talk_menu
) /* voice UI? */
521 talk_spell(text
, true); /* spell initial text */
525 /* These declarations are assigned to the screen on which the key
526 action occurred - pointers save a lot of space over array notation
527 when accessing the same array element countless times */
532 const int button_screen
= 0;
534 struct keyboard_parameters
*pm
;
537 int len_utf8
= utf8length(text
);
540 screens
[l
].clear_display();
542 #ifdef HAVE_MORSE_INPUT
547 /* declare scoped pointers inside screen loops - hide the
548 declarations from previous block level */
549 const int w
= 6; /* sysfixed font width */
550 struct screen
*sc
= &screens
[l
];
553 /* Draw morse code screen with sysfont */
554 sc
->setfont(FONT_SYSFIXED
);
559 /* Draw morse code table with code descriptions. */
560 for (i
= 0; morse_alphabets
[i
] != '\0'; i
++)
565 outline
[0] = morse_alphabets
[i
];
566 sc
->putsxy(x
, y
, outline
);
568 for (j
= 0; (morse_codes
[i
] >> j
) > 0x01; j
++) ;
572 for (j
= 0; j
< morse_len
; j
++)
574 if ((morse_codes
[i
] >> (morse_len
-j
-1)) & 0x01)
575 sc
->fillrect(x
+ j
*4, y
+ 2, 3, 4);
577 sc
->fillrect(x
+ j
*4, y
+ 3, 1, 2);
581 if (x
+ w
*6 >= sc
->getwidth())
584 y
+= 8; /* sysfixed font height */
590 #endif /* HAVE_MORSE_INPUT */
595 struct keyboard_parameters
*pm
= ¶m
[l
];
596 struct screen
*sc
= &screens
[l
];
599 sc
->setfont(pm
->curfont
);
601 k
= pm
->page
*pm
->max_chars
*pm
->lines
;
603 for (i
= j
= 0; j
< pm
->lines
&& k
< pm
->nchars
; k
++)
606 utf8
= utf8encode(pm
->kbd_buf
[k
], outline
);
609 sc
->getstringsize(outline
, &w
, NULL
);
610 sc
->putsxy(i
*pm
->font_w
+ (pm
->font_w
-w
) / 2,
611 j
*pm
->font_h
, outline
);
613 if (++i
>= pm
->max_chars
)
624 struct keyboard_parameters
*pm
= ¶m
[l
];
625 struct screen
*sc
= &screens
[l
];
626 int i
= 0, j
= 0, icon_w
;
627 int text_w
= pm
->text_w
;
628 int sc_w
= sc
->getwidth();
629 int text_margin
= (sc_w
- text_w
* pm
->max_chars_text
) / 2;
631 /* Clear text area one pixel above separator line so any overdraw
633 sc
->set_drawmode(DRMODE_SOLID
| DRMODE_INVERSEVID
);
634 sc
->fillrect(0, pm
->main_y
- pm
->keyboard_margin
- 1,
635 sc_w
, pm
->font_h
+ 4);
636 sc
->set_drawmode(DRMODE_SOLID
);
638 sc
->hline(0, sc_w
- 1, pm
->main_y
- pm
->keyboard_margin
);
640 /* write out the text */
641 sc
->setfont(pm
->curfont
);
643 pm
->curpos
= MIN(editpos
, pm
->max_chars_text
644 - MIN(len_utf8
- editpos
, 2));
645 pm
->leftpos
= editpos
- pm
->curpos
;
646 utf8
= text
+ utf8seek(text
, pm
->leftpos
);
648 while (*utf8
&& i
< pm
->max_chars_text
)
650 outline
[j
++] = *utf8
++;
652 if ((*utf8
& MASK
) != COMP
)
657 sc
->getstringsize(outline
, &w
, NULL
);
658 sc
->putsxy(text_margin
+ i
*text_w
+ (text_w
-w
)/2,
659 pm
->main_y
, outline
);
664 icon_w
= get_icon_width(l
);
667 /* Draw nicer bitmap arrow if room, else settle for "<". */
668 if (text_margin
>= icon_w
)
670 screen_put_icon_with_offset(sc
, 0, 0,
671 (text_margin
- icon_w
) / 2,
672 pm
->main_y
, Icon_Reverse_Cursor
);
677 sc
->getstringsize("<", &w
, NULL
);
678 sc
->putsxy(text_margin
- w
, pm
->main_y
, "<");
682 if (len_utf8
- pm
->leftpos
> pm
->max_chars_text
)
684 /* Draw nicer bitmap arrow if room, else settle for ">". */
685 if (text_margin
>= icon_w
)
687 screen_put_icon_with_offset(sc
, 0, 0,
688 sc_w
- (text_margin
+ icon_w
) / 2,
689 pm
->main_y
, Icon_Cursor
);
693 sc
->putsxy(sc_w
- text_margin
, pm
->main_y
, ">");
698 i
= text_margin
+ pm
->curpos
* text_w
;
701 sc
->vline(i
, pm
->main_y
, pm
->main_y
+ pm
->font_h
- 1);
703 if (pm
->hangul
) /* draw underbar */
704 sc
->hline(i
- text_w
, i
, pm
->main_y
+ pm
->font_h
- 1);
707 cur_blink
= !cur_blink
;
709 #ifdef HAVE_BUTTONBAR
710 /* draw the button bar */
711 gui_buttonbar_set(&buttonbar
, "Shift", "OK", "Del");
712 gui_buttonbar_draw(&buttonbar
);
717 struct keyboard_parameters
*pm
= ¶m
[l
];
718 struct screen
*sc
= &screens
[l
];
720 sc
->set_drawmode(DRMODE_COMPLEMENT
);
723 sc
->fillrect(0, pm
->main_y
- pm
->keyboard_margin
+ 2,
724 sc
->getwidth(), pm
->font_h
+ 2);
725 else /* highlight the key that has focus */
727 #ifdef HAVE_MORSE_INPUT
730 sc
->fillrect(pm
->font_w
*pm
->x
, pm
->font_h
*pm
->y
,
731 pm
->font_w
, pm
->font_h
);
732 sc
->set_drawmode(DRMODE_SOLID
);
738 button
= get_action(CONTEXT_KEYBOARD
, HZ
/2);
740 button_screen
= (get_action_statuscode(NULL
) & ACTION_REMOTE
) ? 1 : 0;
742 pm
= ¶m
[button_screen
];
743 sc
= &screens
[button_screen
];
745 #if defined(KBD_MODES) || defined(HAVE_MORSE_INPUT)
746 /* Remap some buttons to allow to move
747 * cursor in line edit mode and morse mode. */
748 #if defined(KBD_MODES) && defined(HAVE_MORSE_INPUT)
749 if (pm
->line_edit
|| morse_mode
)
750 #elif defined(KBD_MODES)
752 #else /* defined(HAVE_MORSE_INPUT) */
756 if (button
== ACTION_KBD_LEFT
)
757 button
= ACTION_KBD_CURSOR_LEFT
;
758 if (button
== ACTION_KBD_RIGHT
)
759 button
= ACTION_KBD_CURSOR_RIGHT
;
761 /* select doubles as backspace in line_edit */
762 if (pm
->line_edit
&& button
== ACTION_KBD_SELECT
)
763 button
= ACTION_KBD_BACKSPACE
;
766 #endif /* defined(KBD_MODES) || defined(HAVE_MORSE_INPUT) */
770 case ACTION_KBD_DONE
:
771 /* accepts what was entered and continues */
776 case ACTION_KBD_ABORT
:
781 case ACTION_KBD_PAGE_FLIP
:
782 #ifdef HAVE_MORSE_INPUT
786 if (++pm
->page
>= pm
->pages
)
793 #if defined(HAVE_MORSE_INPUT) && defined(KBD_TOGGLE_INPUT)
794 case ACTION_KBD_MORSE_INPUT
:
795 morse_mode
= !morse_mode
;
799 struct keyboard_parameters
*pm
= ¶m
[l
];
800 struct screen
*sc
= &screens
[l
];
803 pm
->main_y
= sc
->getheight() - pm
->font_h
- BUTTONBAR_HEIGHT
;
805 pm
->main_y
= pm
->old_main_y
;
807 /* FIXME: We should talk something like Morse mode.. */
809 #endif /* HAVE_MORSE_INPUT && KBD_TOGGLE_INPUT */
811 case ACTION_KBD_RIGHT
:
812 if (++pm
->x
>= pm
->max_chars
)
814 #ifndef KBD_PAGE_FLIP
815 /* no dedicated flip key - flip page on wrap */
816 if (++pm
->page
>= pm
->pages
)
826 case ACTION_KBD_LEFT
:
829 #ifndef KBD_PAGE_FLIP
830 /* no dedicated flip key - flip page on wrap */
832 pm
->page
= pm
->pages
- 1;
834 pm
->x
= pm
->max_chars
- 1;
841 case ACTION_KBD_DOWN
:
842 #ifdef HAVE_MORSE_INPUT
846 pm
->line_edit
= !pm
->line_edit
;
852 #endif /* HAVE_MORSE_INPUT */
857 pm
->line_edit
= false;
859 else if (++pm
->y
>= pm
->lines
)
861 pm
->line_edit
= true;
865 if (++pm
->y
>= pm
->lines
)
878 #ifdef HAVE_MORSE_INPUT
882 pm
->line_edit
= !pm
->line_edit
;
888 #endif /* HAVE_MORSE_INPUT */
892 pm
->y
= pm
->lines
- 1;
893 pm
->line_edit
= false;
895 else if (--pm
->y
< 0)
897 pm
->line_edit
= true;
902 pm
->y
= pm
->lines
- 1;
913 #ifdef HAVE_MORSE_INPUT
914 case ACTION_KBD_MORSE_SELECT
:
915 if (morse_mode
&& morse_reading
)
918 if ((current_tick
- morse_tick
) > HZ
/5)
922 #endif /* HAVE_MORSE_INPUT */
924 case ACTION_KBD_SELECT
:
925 #ifdef HAVE_MORSE_INPUT
928 morse_tick
= current_tick
;
932 morse_reading
= true;
937 #endif /* HAVE_MORSE_INPUT */
939 /* inserts the selected char */
940 /* find input char */
943 /* check for hangul input */
944 if (ch
>= 0x3131 && ch
<= 0x3163)
950 pm
->hlead
= pm
->hvowel
= pm
->htail
= 0;
963 { /* previous hangul complete */
964 /* check whether tail is actually lead of next char */
965 tmp
= hangul_join(pm
->htail
, ch
, 0);
969 tmp
= hangul_join(pm
->hlead
, pm
->hvowel
, 0);
970 kbd_delchar(text
, &editpos
);
971 kbd_inschar(text
, buflen
, &editpos
, tmp
);
972 /* insert dummy char */
973 kbd_inschar(text
, buflen
, &editpos
, ' ');
974 pm
->hlead
= pm
->htail
;
980 pm
->hvowel
= pm
->htail
= 0;
985 /* combine into hangul */
986 tmp
= hangul_join(pm
->hlead
, pm
->hvowel
, pm
->htail
);
990 kbd_delchar(text
, &editpos
);
995 pm
->hvowel
= pm
->htail
= 0;
1005 kbd_inschar(text
, buflen
, &editpos
, ch
);
1007 if (global_settings
.talk_menu
) /* voice UI? */
1008 talk_spell(text
, false); /* speak revised text */
1012 case ACTION_KBD_BACKSPACE
:
1017 else if (pm
->hvowel
)
1023 kbd_delchar(text
, &editpos
);
1028 ch
= hangul_join(pm
->hlead
, pm
->hvowel
, pm
->htail
);
1031 kbd_inschar(text
, buflen
, &editpos
, ch
);
1034 if (global_settings
.talk_menu
) /* voice UI? */
1035 talk_spell(text
, false); /* speak revised text */
1038 case ACTION_KBD_CURSOR_RIGHT
:
1041 if (editpos
< len_utf8
)
1043 int c
= utf8seek(text
, ++editpos
);
1044 kbd_spellchar(text
[c
]);
1046 #if CONFIG_CODEC == SWCODEC
1047 else if (global_settings
.talk_menu
)
1048 pcmbuf_beep(1000, 150, 1500);
1052 case ACTION_KBD_CURSOR_LEFT
:
1057 int c
= utf8seek(text
, --editpos
);
1058 kbd_spellchar(text
[c
]);
1060 #if CONFIG_CODEC == SWCODEC
1061 else if (global_settings
.talk_menu
)
1062 pcmbuf_beep(1000, 150, 1500);
1067 #ifdef HAVE_MORSE_INPUT
1071 logf("Morse: 0x%02x", morse_code
);
1072 morse_reading
= false;
1074 for (j
= 0; morse_alphabets
[j
] != '\0'; j
++)
1076 if (morse_codes
[j
] == morse_code
)
1080 if (morse_alphabets
[j
] == '\0')
1082 logf("Morse code not found");
1086 /* turn off hangul input */
1088 param
[l
].hangul
= false;
1089 kbd_inschar(text
, buflen
, &editpos
, morse_alphabets
[j
]);
1091 if (global_settings
.talk_menu
) /* voice UI? */
1092 talk_spell(text
, false); /* speak revised text */
1094 #endif /* HAVE_MORSE_INPUT */
1098 if (default_event_handler(button
) == SYS_USB_CONNECTED
)
1101 screens
[l
].setfont(FONT_SYSFIXED
);
1107 if (button
!= BUTTON_NONE
)
1113 #ifdef HAVE_BUTTONBAR
1114 global_settings
.buttonbar
= buttonbar_config
;
1118 splash(HZ
/2, ID2P(LANG_CANCEL
));
1120 #if defined(HAVE_MORSE_INPUT) && defined(KBD_TOGGLE_INPUT)
1121 if(global_settings
.morse_input
!= morse_mode
)
1123 global_settings
.morse_input
= morse_mode
;
1126 #endif /* HAVE_MORSE_INPUT && KBD_TOGGLE_INPUT */
1130 screens
[l
].setfont(FONT_UI
);
1131 viewportmanager_theme_undo(l
);