| /*************************************************************************** |
| * __________ __ ___. |
| * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| * \/ \/ \/ \/ \/ |
| * $Id$ |
| * |
| * Copyright (C) 2002 by Björn Stenberg |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ****************************************************************************/ |
| #include "lcd.h" |
| #include "button.h" |
| #include "kernel.h" |
| #include "system.h" |
| #include "version.h" |
| #include "sprintf.h" |
| #include <string.h> |
| #include "settings.h" |
| #include "statusbar.h" |
| #include "talk.h" |
| #include "misc.h" |
| #include "rbunicode.h" |
| #include "lang.h" |
| |
| #define KBD_BUF_SIZE 64 |
| #define KEYBOARD_PAGES 3 |
| |
| static unsigned short *kbd_setupkeys(int page, int* len) |
| { |
| static unsigned short kbdline[KBD_BUF_SIZE]; |
| const unsigned char *p; |
| int i = 0; |
| |
| switch (page) |
| { |
| case 0: /* Capitals */ |
| p = "ABCDEFGHIJKLMNOPQRSTUVWXYZÃÃÃÃÃÃ
" |
| "ÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃ"; |
| break; |
| |
| case 1: /* Small */ |
| p = "abcdefghijklmnopqrstuvwxyzÃà áâãä" |
| "åçèéêëìÃîïñòóôõöøùúûüýÿ"; |
| break; |
| |
| default: /* Others */ |
| p = " !\"#$%&'()*+,-./0123456789:;<=>?@[]_{}~"; |
| break; |
| } |
| |
| while (*p) |
| p = utf8decode(p, &kbdline[i++]); |
| |
| *len = i; |
| |
| return kbdline; |
| } |
| |
| /* Delimiters for highlighting the character selected for insertion */ |
| #define KEYBOARD_INSERT_LEFT 0xe110 |
| #define KEYBOARD_INSERT_RIGHT 0xe10f |
| |
| #define KEYBOARD_CURSOR 0x7f |
| #define KEYBOARD_ARROW 0xe10c |
| |
| /* helper function to spell a char if voice UI is enabled */ |
| static void kbd_spellchar(unsigned short c) |
| { |
| if (global_settings.talk_menu) /* voice UI? */ |
| { |
| unsigned char tmp[5]; |
| /* store char to pass to talk_spell */ |
| unsigned char* utf8 = utf8encode(c, tmp); |
| *utf8 = 0; |
| |
| if(c == ' ') |
| talk_id(VOICE_BLANK, false); |
| else |
| talk_spell(tmp, false); |
| } |
| } |
| |
| static void say_edit(void) |
| { |
| if (global_settings.talk_menu) |
| talk_id(VOICE_EDIT, false); |
| } |
| |
| int kbd_input(char* text, int buflen) |
| { |
| bool done = false; |
| bool redraw = true; |
| bool line_edit = false; |
| int page = 0, x = 0; |
| int linelen; |
| |
| int len, len_utf8, i, j; |
| int editpos, curpos, leftpos; |
| unsigned short *line = kbd_setupkeys(page, &linelen); |
| unsigned char temptext[36]; |
| unsigned char *utf8; |
| |
| int button, lastbutton = 0; |
| |
| editpos = utf8length(text); |
| |
| if (global_settings.talk_menu) /* voice UI? */ |
| talk_spell(text, true); /* spell initial text */ |
| |
| while (!done) |
| { |
| len = strlen(text); |
| len_utf8 = utf8length(text); |
| |
| if (redraw) |
| { |
| if (line_edit) |
| { |
| lcd_putc(0, 0, ' '); |
| lcd_putc(0, 1, KEYBOARD_ARROW); |
| } |
| else |
| { |
| lcd_putc(0, 0, KEYBOARD_ARROW); |
| lcd_putc(0, 1, ' '); |
| } |
| |
| lcd_putc(1, 0, KEYBOARD_INSERT_LEFT); |
| lcd_putc(2, 0, line[x]); |
| lcd_putc(3, 0, KEYBOARD_INSERT_RIGHT); |
| for (i = 1; i < 8; i++) |
| { |
| lcd_putc(i + 3, 0, line[(x+i)%linelen]); |
| } |
| |
| /* write out the text */ |
| curpos = MIN(MIN(editpos, 10 - MIN(len_utf8 - editpos, 3)), 9); |
| leftpos = editpos - curpos; |
| if (!leftpos) { |
| utf8 = text + utf8seek(text, leftpos); |
| i = 0; |
| j = 0; |
| } else { |
| temptext[0] = '<'; |
| i = 1; |
| j = 1; |
| utf8 = text + utf8seek(text, leftpos+1); |
| } |
| while (*utf8 && i < 10) { |
| temptext[j++] = *utf8++; |
| if ((*utf8 & MASK) != COMP) |
| i++; |
| } |
| temptext[j] = 0; |
| |
| |
| if (len_utf8 - leftpos > 10) { |
| utf8 = temptext + utf8seek(temptext, 9); |
| *utf8++ = '>'; |
| *utf8 = 0; |
| } |
| |
| lcd_remove_cursor(); |
| lcd_puts(1, 1, temptext); |
| lcd_put_cursor(curpos + 1, 1, KEYBOARD_CURSOR); |
| |
| gui_syncstatusbar_draw(&statusbars, true); |
| } |
| |
| /* The default action is to redraw */ |
| redraw = true; |
| |
| button = button_get_w_tmo(HZ/2); |
| switch (button) |
| { |
| case BUTTON_STOP: /* abort */ |
| return -1; |
| break; |
| |
| case BUTTON_MENU: /* page flip */ |
| if (++page == KEYBOARD_PAGES) |
| page = 0; |
| line = kbd_setupkeys(page, &linelen); |
| if (x > linelen - 1) |
| x = linelen - 1; |
| kbd_spellchar(line[x]); |
| break; |
| |
| case BUTTON_ON: /* toggle mode */ |
| line_edit = !line_edit; |
| if (line_edit) |
| say_edit(); |
| else |
| kbd_spellchar(line[x]); |
| break; |
| |
| case BUTTON_RIGHT: |
| case BUTTON_RIGHT | BUTTON_REPEAT: |
| if (line_edit) |
| { |
| if (editpos < len_utf8) |
| { |
| editpos++; |
| int c = utf8seek(text, editpos); |
| kbd_spellchar(text[c]); |
| } |
| } |
| else |
| { |
| if (++x >= linelen) |
| x = 0; |
| kbd_spellchar(line[x]); |
| } |
| break; |
| |
| case BUTTON_LEFT: |
| case BUTTON_LEFT | BUTTON_REPEAT: |
| if (line_edit) |
| { |
| if (editpos) |
| { |
| editpos--; |
| int c = utf8seek(text, editpos); |
| kbd_spellchar(text[c]); |
| } |
| } |
| else |
| { |
| if (--x < 0) |
| x = linelen - 1; |
| kbd_spellchar(line[x]); |
| } |
| break; |
| |
| case BUTTON_PLAY | BUTTON_REPEAT: |
| /* accepts what was entered and continues */ |
| done = true; |
| break; |
| |
| case BUTTON_PLAY | BUTTON_REL: |
| if (lastbutton != BUTTON_PLAY) |
| break; |
| if (line_edit) /* backspace in line_edit */ |
| { |
| if (editpos > 0) |
| { |
| utf8 = text + utf8seek(text, editpos); |
| i = 0; |
| do { |
| i++; |
| utf8--; |
| } while ((*utf8 & MASK) == COMP); |
| while (utf8[i]) { |
| *utf8 = utf8[i]; |
| utf8++; |
| } |
| *utf8 = 0; |
| editpos--; |
| } |
| } |
| else /* inserts the selected char */ |
| { |
| utf8 = utf8encode(line[x], temptext); |
| *utf8 = 0; |
| j = strlen(temptext); |
| if (len + j < buflen) |
| { |
| int k = len_utf8; |
| for (i = len+j; k >= editpos; i--) { |
| text[i] = text[i-j]; |
| if ((text[i] & MASK) != COMP) |
| k--; |
| } |
| while (j--) |
| text[i--] = temptext[j]; |
| editpos++; |
| } |
| } |
| if (global_settings.talk_menu) /* voice UI? */ |
| talk_spell(text, false); /* speak revised text */ |
| break; |
| |
| case BUTTON_NONE: |
| gui_syncstatusbar_draw(&statusbars, false); |
| redraw = false; |
| break; |
| |
| default: |
| default_event_handler(button); |
| break; |
| } |
| if (button != BUTTON_NONE) |
| lastbutton = button; |
| } |
| |
| return 0; |
| } |
| |