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 ****************************************************************************/
23 #include "string-extra.h"
29 #include "rbunicode.h"
30 #include "buttonbar.h"
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 || (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
53 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
54 || (CONFIG_KEYPAD == IPOD_4G_PAD) \
55 || (CONFIG_KEYPAD == IRIVER_H10_PAD) \
56 || (CONFIG_KEYPAD == GIGABEAT_PAD) \
57 || (CONFIG_KEYPAD == GIGABEAT_S_PAD) \
58 || (CONFIG_KEYPAD == MROBE100_PAD) \
59 || (CONFIG_KEYPAD == SANSA_E200_PAD) \
60 || (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) \
61 || (CONFIG_KEYPAD == PHILIPS_SA9200_PAD) \
62 || (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
63 /* certain key combos toggle input mode between keyboard input and Morse input */
64 #define KBD_TOGGLE_INPUT
67 #define CHANGED_PICKER 1
68 #define CHANGED_CURSOR 2
69 #define CHANGED_TEXT 3
71 struct keyboard_parameters
73 unsigned short kbd_buf
[KBD_BUF_SIZE
];
74 unsigned short max_line_len
;
82 #ifdef HAVE_MORSE_INPUT
103 int editpos
; /* Edit position on all screens */
104 bool cur_blink
; /* Cursor on/off flag */
106 unsigned short hlead
, hvowel
, htail
;
107 #ifdef HAVE_MORSE_INPUT
110 unsigned char morse_code
;
116 static struct keyboard_parameters kbd_param
[NB_SCREENS
];
117 static bool kbd_loaded
= false;
119 #ifdef HAVE_MORSE_INPUT
120 /* FIXME: We should put this to a configuration file. */
121 static const char *morse_alphabets
=
122 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
123 static const unsigned char morse_codes
[] = {
124 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
125 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
126 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
127 0x73,0x55,0x4c,0x61,0x5a,0x80 };
130 /* Loads a custom keyboard into memory
131 call with NULL to reset keyboard */
132 int load_kbd(unsigned char* filename
)
135 int i
, line_len
, max_line_len
;
136 unsigned char buf
[4];
138 if (filename
== NULL
)
144 fd
= open_utf8(filename
, O_RDONLY
|O_BINARY
);
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 };
158 for (count
= 0; count
< ARRAYLEN(sizes
); count
++)
160 if (buf
[0] < sizes
[count
])
164 if (count
>= ARRAYLEN(sizes
))
165 continue; /* Invalid size. */
167 if (read(fd
, &buf
[1], count
) != (ssize_t
)count
)
174 utf8decode(buf
, &ch
);
175 if (ch
!= 0xFEFF && ch
!= '\r') /* skip BOM & carriage returns */
178 kbd_param
[l
].kbd_buf
[i
] = ch
;
182 if (max_line_len
< line_len
)
183 max_line_len
= line_len
;
194 if (max_line_len
< line_len
)
195 max_line_len
= line_len
;
199 struct keyboard_parameters
*pm
= &kbd_param
[l
];
201 /* initialize parameters */
202 pm
->x
= pm
->y
= pm
->page
= 0;
203 pm
->default_lines
= 0;
204 pm
->max_line_len
= max_line_len
;
210 /* helper function to spell a char */
211 static void kbd_spellchar(unsigned short c
)
213 unsigned char tmp
[5];
214 /* store char to pass to talk_spell */
215 unsigned char* utf8
= utf8encode(c
, tmp
);
219 talk_id(VOICE_BLANK
, false);
221 talk_spell(tmp
, false);
224 static void kbd_inschar(struct edit_state
*state
, unsigned short ch
)
227 unsigned char tmp
[4];
230 len
= strlen(state
->text
);
231 utf8
= utf8encode(ch
, tmp
);
232 j
= (long)utf8
- (long)tmp
;
234 if (len
+ j
< state
->buflen
)
236 i
= utf8seek(state
->text
, state
->editpos
);
237 utf8
= state
->text
+ i
;
238 memmove(utf8
+ j
, utf8
, len
- i
+ 1);
239 memcpy(utf8
, tmp
, j
);
241 state
->changed
= CHANGED_TEXT
;
245 static void kbd_delchar(struct edit_state
*state
)
250 if (state
->editpos
> 0)
253 len
= strlen(state
->text
);
254 i
= utf8seek(state
->text
, state
->editpos
);
255 utf8
= state
->text
+ i
;
256 j
= utf8seek(utf8
, 1);
257 memmove(utf8
, utf8
+ j
, len
- i
- j
+ 1);
258 state
->changed
= CHANGED_TEXT
;
262 /* Lookup k value based on state of param (pm) */
263 static unsigned short get_kbd_ch(const struct keyboard_parameters
*pm
)
265 int k
= (pm
->page
*pm
->lines
+ pm
->y
)*pm
->max_chars
+ pm
->x
;
266 return (k
< pm
->nchars
)? pm
->kbd_buf
[k
]: ' ';
269 static void kbd_calc_params(struct keyboard_parameters
*pm
,
270 struct screen
*sc
, struct edit_state
*state
);
271 static void kbd_draw_picker(struct keyboard_parameters
*pm
,
272 struct screen
*sc
, struct edit_state
*state
);
273 static void kbd_draw_edit_line(struct keyboard_parameters
*pm
,
274 struct screen
*sc
, struct edit_state
*state
);
275 static void kbd_insert_selected(struct keyboard_parameters
*pm
,
276 struct edit_state
*state
);
277 static void kbd_backspace(struct edit_state
*state
);
278 static void kbd_move_cursor(struct edit_state
*state
, int dir
);
279 static void kbd_move_picker_horizontal(struct keyboard_parameters
*pm
,
280 struct edit_state
*state
, int dir
);
281 static void kbd_move_picker_vertical(struct keyboard_parameters
*pm
,
282 struct edit_state
*state
, int dir
);
284 int kbd_input(char* text
, int buflen
)
288 /* This seems to keep the sizes for ARM way down */
289 struct keyboard_parameters
* volatile param
= kbd_param
;
291 struct keyboard_parameters
* const param
= kbd_param
;
293 struct edit_state state
;
294 int l
; /* screen loop variable */
296 int ret
= 0; /* assume success */
299 viewportmanager_theme_enable(l
, false, NULL
);
302 #ifdef HAVE_BUTTONBAR
303 struct gui_buttonbar buttonbar
;
304 bool buttonbar_config
= global_settings
.buttonbar
;
306 global_settings
.buttonbar
= true;
307 gui_buttonbar_init(&buttonbar
);
308 gui_buttonbar_set_display(&buttonbar
, &screens
[SCREEN_MAIN
]);
311 /* initialize state */
313 state
.buflen
= buflen
;
314 /* Initial edit position is after last character */
315 state
.editpos
= utf8length(state
.text
);
316 state
.cur_blink
= true;
317 #ifdef HAVE_MORSE_INPUT
318 state
.morse_mode
= global_settings
.morse_input
;
319 state
.morse_reading
= false;
321 state
.hangul
= false;
326 /* Copy default keyboard to buffer */
329 struct keyboard_parameters
*pm
= ¶m
[l
];
330 const unsigned char *p
;
333 #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96
334 struct screen
*sc
= &screens
[l
];
336 if (sc
->getwidth() >= 160 && sc
->getheight() >= 96)
338 p
= "ABCDEFG abcdefg !?\" @#$%+'\n"
339 "HIJKLMN hijklmn 789 &_()-`\n"
340 "OPQRSTU opqrstu 456 §|{}/<\n"
341 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
342 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
343 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
344 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
345 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;";
347 pm
->default_lines
= 8;
348 pm
->max_line_len
= 26;
351 #endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */
353 p
= "ABCDEFG !?\" @#$%+'\n"
354 "HIJKLMN 789 &_()-`\n"
355 "OPQRSTU 456 §|{}/<\n"
356 "VWXYZ.,0123 ~=[]*>\n"
358 "abcdefg ¢£¤¥¦§©®¬\n"
359 "hijklmn «»°ºª¹²³¶\n"
360 "opqrstu ¯±×÷¡¿µ·¨\n"
363 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
364 "àáâãäåæ ìíîï èéêë\n"
365 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
368 pm
->default_lines
= 4;
369 pm
->max_line_len
= 18;
373 p
= utf8decode(p
, &pm
->kbd_buf
[i
++]);
376 /* initialize parameters */
377 pm
->x
= pm
->y
= pm
->page
= 0;
384 struct keyboard_parameters
*pm
= ¶m
[l
];
385 struct screen
*sc
= &screens
[l
];
386 kbd_calc_params(pm
, sc
, &state
);
389 if (global_settings
.talk_menu
) /* voice UI? */
390 talk_spell(state
.text
, true); /* spell initial text */
394 /* These declarations are assigned to the screen on which the key
395 action occurred - pointers save a lot of space over array notation
396 when accessing the same array element countless times */
401 const int button_screen
= 0;
403 struct keyboard_parameters
*pm
;
406 state
.len_utf8
= utf8length(state
.text
);
410 /* declare scoped pointers inside screen loops - hide the
411 declarations from previous block level */
412 struct keyboard_parameters
*pm
= ¶m
[l
];
413 struct screen
*sc
= &screens
[l
];
415 kbd_draw_picker(pm
, sc
, &state
);
416 kbd_draw_edit_line(pm
, sc
, &state
);
419 #ifdef HAVE_BUTTONBAR
420 /* draw the button bar */
421 gui_buttonbar_set(&buttonbar
, "Shift", "OK", "Del");
422 gui_buttonbar_draw(&buttonbar
);
428 state
.cur_blink
= !state
.cur_blink
;
431 #ifdef HAVE_MORSE_INPUT
432 state
.morse_mode
? CONTEXT_MORSE_INPUT
:
434 CONTEXT_KEYBOARD
, HZ
/2);
436 button_screen
= (get_action_statuscode(NULL
) & ACTION_REMOTE
) ? 1 : 0;
438 pm
= ¶m
[button_screen
];
439 sc
= &screens
[button_screen
];
441 /* Remap some buttons to allow to move
442 * cursor in line edit mode and morse mode. */
444 #ifdef HAVE_MORSE_INPUT
446 #endif /* HAVE_MORSE_INPUT */
449 if (button
== ACTION_KBD_LEFT
)
450 button
= ACTION_KBD_CURSOR_LEFT
;
451 if (button
== ACTION_KBD_RIGHT
)
452 button
= ACTION_KBD_CURSOR_RIGHT
;
457 case ACTION_KBD_DONE
:
458 /* accepts what was entered and continues */
463 case ACTION_KBD_ABORT
:
468 case ACTION_KBD_PAGE_FLIP
:
469 #ifdef HAVE_MORSE_INPUT
470 if (state
.morse_mode
)
473 if (++pm
->page
>= pm
->pages
)
476 state
.changed
= CHANGED_PICKER
;
479 case ACTION_KBD_RIGHT
:
480 kbd_move_picker_horizontal(pm
, &state
, 1);
483 case ACTION_KBD_LEFT
:
484 kbd_move_picker_horizontal(pm
, &state
, -1);
487 case ACTION_KBD_DOWN
:
488 kbd_move_picker_vertical(pm
, &state
, 1);
492 kbd_move_picker_vertical(pm
, &state
, -1);
495 #ifdef HAVE_MORSE_INPUT
496 #ifdef KBD_TOGGLE_INPUT
497 case ACTION_KBD_MORSE_INPUT
:
498 state
.morse_mode
= !state
.morse_mode
;
499 state
.changed
= CHANGED_PICKER
;
503 struct keyboard_parameters
*pm
= ¶m
[l
];
505 pm
->main_y
= pm
->old_main_y
;
509 #endif /* KBD_TOGGLE_INPUT */
511 case ACTION_KBD_MORSE_SELECT
:
512 if (state
.morse_mode
&& state
.morse_reading
)
514 state
.morse_code
<<= 1;
515 if ((current_tick
- state
.morse_tick
) > HZ
/5)
516 state
.morse_code
|= 0x01;
519 #endif /* HAVE_MORSE_INPUT */
521 case ACTION_KBD_SELECT
:
522 /* select doubles as backspace in line_edit */
524 kbd_backspace(&state
);
526 #ifdef HAVE_MORSE_INPUT
527 if (state
.morse_mode
)
529 state
.morse_tick
= current_tick
;
531 if (!state
.morse_reading
)
533 state
.morse_reading
= true;
534 state
.morse_code
= 1;
538 #endif /* HAVE_MORSE_INPUT */
539 kbd_insert_selected(pm
, &state
);
542 case ACTION_KBD_BACKSPACE
:
543 kbd_backspace(&state
);
546 case ACTION_KBD_CURSOR_RIGHT
:
547 kbd_move_cursor(&state
, 1);
550 case ACTION_KBD_CURSOR_LEFT
:
551 kbd_move_cursor(&state
, -1);
555 #ifdef HAVE_MORSE_INPUT
556 if (state
.morse_reading
)
559 logf("Morse: 0x%02x", state
.morse_code
);
560 state
.morse_reading
= false;
562 for (j
= 0; morse_alphabets
[j
] != '\0'; j
++)
564 if (morse_codes
[j
] == state
.morse_code
)
568 if (morse_alphabets
[j
] == '\0')
570 logf("Morse code not found");
574 /* turn off hangul input */
575 state
.hangul
= false;
576 kbd_inschar(&state
, morse_alphabets
[j
]);
578 #endif /* HAVE_MORSE_INPUT */
582 if (default_event_handler(button
) == SYS_USB_CONNECTED
)
585 screens
[l
].setfont(FONT_SYSFIXED
);
591 if (button
!= ACTION_NONE
)
593 state
.cur_blink
= true;
595 if (global_settings
.talk_menu
) /* voice UI? */
597 if (state
.changed
== CHANGED_PICKER
)
601 talk_id(VOICE_EDIT
, false);
604 #ifdef HAVE_MORSE_INPUT
605 /* FIXME: We should talk something like Morse mode.. */
606 if (!state
.morse_mode
)
613 else if (state
.changed
== CHANGED_CURSOR
)
615 int c
= utf8seek(state
.text
, state
.editpos
);
616 kbd_spellchar(state
.text
[c
]);
618 else if (state
.changed
== CHANGED_TEXT
)
619 talk_spell(state
.text
, false); /* speak revised text */
624 #ifdef HAVE_BUTTONBAR
625 global_settings
.buttonbar
= buttonbar_config
;
629 splash(HZ
/2, ID2P(LANG_CANCEL
));
631 #if defined(HAVE_MORSE_INPUT) && defined(KBD_TOGGLE_INPUT)
632 if (global_settings
.morse_input
!= state
.morse_mode
)
634 global_settings
.morse_input
= state
.morse_mode
;
637 #endif /* HAVE_MORSE_INPUT && KBD_TOGGLE_INPUT */
641 screens
[l
].setfont(FONT_UI
);
642 viewportmanager_theme_undo(l
, false);
647 static void kbd_calc_params(struct keyboard_parameters
*pm
,
648 struct screen
*sc
, struct edit_state
*state
)
651 const unsigned char *p
;
653 int icon_w
, sc_w
, sc_h
, w
;
656 pm
->curfont
= pm
->default_lines
? FONT_SYSFIXED
: FONT_UI
;
657 font
= font_get(pm
->curfont
);
658 pm
->font_h
= font
->height
;
660 /* check if FONT_UI fits the screen */
661 if (2*pm
->font_h
+ 3 + BUTTONBAR_HEIGHT
> sc
->getheight())
663 pm
->curfont
= FONT_SYSFIXED
;
664 font
= font_get(FONT_SYSFIXED
);
665 pm
->font_h
= font
->height
;
668 /* find max width of keyboard glyphs.
669 * since we're going to be adding spaces,
670 * max width is at least their width */
671 pm
->font_w
= font_get_width(font
, ' ');
672 for (i
= 0; i
< pm
->nchars
; i
++)
674 if (pm
->kbd_buf
[i
] != '\n')
676 w
= font_get_width(font
, pm
->kbd_buf
[i
]);
682 /* Find max width for text string */
683 pm
->text_w
= pm
->font_w
;
687 p
= utf8decode(p
, &ch
);
688 w
= font_get_width(font
, ch
);
693 /* calculate how many characters to put in a row. */
694 icon_w
= get_icon_width(sc
->screen_type
);
695 sc_w
= sc
->getwidth();
696 if (pm
->font_w
< sc_w
/ pm
->max_line_len
)
697 pm
->font_w
= sc_w
/ pm
->max_line_len
;
698 pm
->max_chars
= sc_w
/ pm
->font_w
;
699 pm
->max_chars_text
= (sc_w
- icon_w
* 2 - 2) / pm
->text_w
;
700 if (pm
->max_chars_text
< 3 && icon_w
> pm
->text_w
)
701 pm
->max_chars_text
= sc_w
/ pm
->text_w
- 2;
705 /* Pad lines with spaces */
706 while (i
< pm
->nchars
)
708 if (pm
->kbd_buf
[i
] == '\n')
710 int k
= pm
->max_chars
- i
% ( pm
->max_chars
) - 1;
713 if (k
== pm
->max_chars
- 1)
717 for (j
= i
; j
< pm
->nchars
; j
++)
719 pm
->kbd_buf
[j
] = pm
->kbd_buf
[j
+ 1];
724 if (pm
->nchars
+ k
- 1 >= KBD_BUF_SIZE
)
725 { /* We don't want to overflow the buffer */
726 k
= KBD_BUF_SIZE
- pm
->nchars
;
729 for (j
= pm
->nchars
+ k
- 1; j
> i
+ k
; j
--)
731 pm
->kbd_buf
[j
] = pm
->kbd_buf
[j
-k
];
739 pm
->kbd_buf
[i
++] = ' ';
749 pm
->kbd_buf
[pm
->nchars
++] = ' ';
751 /* calculate pm->pages and pm->lines */
752 sc_h
= sc
->getheight();
753 pm
->lines
= (sc_h
- BUTTONBAR_HEIGHT
) / pm
->font_h
- 1;
755 if (pm
->default_lines
&& pm
->lines
> pm
->default_lines
)
756 pm
->lines
= pm
->default_lines
;
758 pm
->keyboard_margin
= sc_h
- BUTTONBAR_HEIGHT
759 - (pm
->lines
+1)*pm
->font_h
;
761 if (pm
->keyboard_margin
< 3 && pm
->lines
> 1)
764 pm
->keyboard_margin
+= pm
->font_h
;
767 if (pm
->keyboard_margin
> DEFAULT_MARGIN
)
768 pm
->keyboard_margin
= DEFAULT_MARGIN
;
770 total_lines
= (pm
->nchars
+ pm
->max_chars
- 1) / pm
->max_chars
;
771 pm
->pages
= (total_lines
+ pm
->lines
- 1) / pm
->lines
;
772 pm
->lines
= (total_lines
+ pm
->pages
- 1) / pm
->pages
;
774 pm
->main_y
= pm
->font_h
*pm
->lines
+ pm
->keyboard_margin
;
775 pm
->keyboard_margin
-= pm
->keyboard_margin
/2;
777 #ifdef HAVE_MORSE_INPUT
778 pm
->old_main_y
= sc_h
- pm
->font_h
- BUTTONBAR_HEIGHT
;
779 if (state
->morse_mode
)
782 pm
->main_y
= pm
->old_main_y
;
788 static void kbd_draw_picker(struct keyboard_parameters
*pm
,
789 struct screen
*sc
, struct edit_state
*state
)
792 #ifdef HAVE_MORSE_INPUT
793 if (state
->morse_mode
)
795 const int w
= 6, h
= 8; /* sysfixed font width, height */
797 int sc_w
= sc
->getwidth(), sc_h
= pm
->main_y
- pm
->keyboard_margin
- 1;
799 /* Draw morse code screen with sysfont */
800 sc
->setfont(FONT_SYSFIXED
);
805 /* Draw morse code table with code descriptions. */
806 for (i
= 0; morse_alphabets
[i
] != '\0'; i
++)
810 outline
[0] = morse_alphabets
[i
];
811 sc
->putsxy(x
, y
, outline
);
813 morse_code
= morse_codes
[i
];
814 for (j
= 0; morse_code
> 0x01; morse_code
>>= 1)
818 morse_code
= morse_codes
[i
];
819 for (; morse_code
> 0x01; morse_code
>>= 1)
822 if (morse_code
& 0x01)
823 sc
->fillrect(x
, y
+ 2, 3, 4);
825 sc
->fillrect(x
, y
+ 3, 1, 2);
841 #endif /* HAVE_MORSE_INPUT */
846 sc
->setfont(pm
->curfont
);
848 k
= pm
->page
*pm
->max_chars
*pm
->lines
;
850 for (i
= j
= 0; k
< pm
->nchars
; k
++)
854 utf8
= utf8encode(pm
->kbd_buf
[k
], outline
);
857 sc
->getstringsize(outline
, &w
, NULL
);
858 sc
->putsxy(i
*pm
->font_w
+ (pm
->font_w
-w
) / 2,
859 j
*pm
->font_h
, outline
);
861 if (++i
>= pm
->max_chars
)
864 if (++j
>= pm
->lines
)
871 /* highlight the key that has focus */
872 sc
->set_drawmode(DRMODE_COMPLEMENT
);
873 sc
->fillrect(pm
->font_w
*pm
->x
, pm
->font_h
*pm
->y
,
874 pm
->font_w
, pm
->font_h
);
875 sc
->set_drawmode(DRMODE_SOLID
);
880 static void kbd_draw_edit_line(struct keyboard_parameters
*pm
,
881 struct screen
*sc
, struct edit_state
*state
)
885 int i
= 0, j
= 0, icon_w
, w
;
886 int sc_w
= sc
->getwidth();
887 int y
= pm
->main_y
- pm
->keyboard_margin
;
888 int text_margin
= (sc_w
- pm
->text_w
* pm
->max_chars_text
) / 2;
890 /* Clear text area one pixel above separator line so any overdraw
892 screen_clear_area(sc
, 0, y
- 1, sc_w
, pm
->font_h
+ 6);
894 sc
->hline(0, sc_w
- 1, y
);
896 /* write out the text */
897 sc
->setfont(pm
->curfont
);
899 pm
->leftpos
= MAX(0, MIN(state
->len_utf8
, state
->editpos
+ 2)
900 - pm
->max_chars_text
);
901 pm
->curpos
= state
->editpos
- pm
->leftpos
;
902 utf8
= state
->text
+ utf8seek(state
->text
, pm
->leftpos
);
904 while (*utf8
&& i
< pm
->max_chars_text
)
906 j
= utf8seek(utf8
, 1);
907 strlcpy(outline
, utf8
, j
+1);
908 sc
->getstringsize(outline
, &w
, NULL
);
909 sc
->putsxy(text_margin
+ i
*pm
->text_w
+ (pm
->text_w
-w
)/2,
910 pm
->main_y
, outline
);
915 icon_w
= get_icon_width(sc
->screen_type
);
918 /* Draw nicer bitmap arrow if room, else settle for "<". */
919 if (text_margin
>= icon_w
)
921 screen_put_icon_with_offset(sc
, 0, 0,
922 (text_margin
- icon_w
) / 2,
923 pm
->main_y
, Icon_Reverse_Cursor
);
927 sc
->getstringsize("<", &w
, NULL
);
928 sc
->putsxy(text_margin
- w
, pm
->main_y
, "<");
932 if (state
->len_utf8
- pm
->leftpos
> pm
->max_chars_text
)
934 /* Draw nicer bitmap arrow if room, else settle for ">". */
935 if (text_margin
>= icon_w
)
937 screen_put_icon_with_offset(sc
, 0, 0,
938 sc_w
- (text_margin
+ icon_w
) / 2,
939 pm
->main_y
, Icon_Cursor
);
943 sc
->putsxy(sc_w
- text_margin
, pm
->main_y
, ">");
948 i
= text_margin
+ pm
->curpos
* pm
->text_w
;
950 if (state
->cur_blink
)
951 sc
->vline(i
, pm
->main_y
, pm
->main_y
+ pm
->font_h
- 1);
953 if (state
->hangul
) /* draw underbar */
954 sc
->hline(i
- pm
->text_w
, i
, pm
->main_y
+ pm
->font_h
- 1);
958 sc
->set_drawmode(DRMODE_COMPLEMENT
);
959 sc
->fillrect(0, y
+ 2, sc_w
, pm
->font_h
+ 2);
960 sc
->set_drawmode(DRMODE_SOLID
);
964 /* inserts the selected char */
965 static void kbd_insert_selected(struct keyboard_parameters
*pm
,
966 struct edit_state
*state
)
968 /* find input char */
969 unsigned short ch
= get_kbd_ch(pm
);
971 /* check for hangul input */
972 if (ch
>= 0x3131 && ch
<= 0x3163)
978 state
->hlead
= state
->hvowel
= state
->htail
= 0;
979 state
->hangul
= true;
986 else if (!state
->htail
)
992 /* previous hangul complete */
993 /* check whether tail is actually lead of next char */
994 tmp
= hangul_join(state
->htail
, ch
, 0);
998 tmp
= hangul_join(state
->hlead
, state
->hvowel
, 0);
1000 kbd_inschar(state
, tmp
);
1001 /* insert dummy char */
1002 kbd_inschar(state
, ' ');
1003 state
->hlead
= state
->htail
;
1009 state
->hvowel
= state
->htail
= 0;
1014 /* combine into hangul */
1015 tmp
= hangul_join(state
->hlead
, state
->hvowel
, state
->htail
);
1024 state
->hvowel
= state
->htail
= 0;
1030 state
->hangul
= false;
1034 kbd_inschar(state
, ch
);
1037 static void kbd_backspace(struct edit_state
*state
)
1044 else if (state
->hvowel
)
1047 state
->hangul
= false;
1055 ch
= hangul_join(state
->hlead
, state
->hvowel
, state
->htail
);
1058 kbd_inschar(state
, ch
);
1062 static void kbd_move_cursor(struct edit_state
*state
, int dir
)
1064 state
->hangul
= false;
1065 state
->editpos
+= dir
;
1067 if (state
->editpos
>= 0 && state
->editpos
<= state
->len_utf8
)
1069 state
->changed
= CHANGED_CURSOR
;
1073 state
->editpos
-= dir
;
1074 #if CONFIG_CODEC == SWCODEC
1075 if (global_settings
.talk_menu
)
1076 pcmbuf_beep(1000, 150, 1500);
1081 static void kbd_move_picker_horizontal(struct keyboard_parameters
*pm
,
1082 struct edit_state
*state
, int dir
)
1084 state
->changed
= CHANGED_PICKER
;
1090 pm
->page
= pm
->pages
- 1;
1091 pm
->x
= pm
->max_chars
- 1;
1093 else if (pm
->x
>= pm
->max_chars
)
1095 if (++pm
->page
>= pm
->pages
)
1101 static void kbd_move_picker_vertical(struct keyboard_parameters
*pm
,
1102 struct edit_state
*state
, int dir
)
1104 state
->changed
= CHANGED_PICKER
;
1106 #ifdef HAVE_MORSE_INPUT
1107 if (state
->morse_mode
)
1109 pm
->line_edit
= !pm
->line_edit
;
1112 #endif /* HAVE_MORSE_INPUT */
1117 pm
->y
= (dir
> 0 ? 0 : pm
->lines
- 1);
1118 pm
->line_edit
= false;
1120 else if (pm
->y
< 0 || pm
->y
>= pm
->lines
)
1122 pm
->line_edit
= true;