diff --git a/apps/action.h b/apps/action.h index e54d5de..e07ab17 100644 --- a/apps/action.h +++ b/apps/action.h @@ -243,6 +243,8 @@ enum { ACTION_KBD_DOWN, ACTION_KBD_MORSE_INPUT, ACTION_KBD_MORSE_SELECT, + ACTION_KBD_SCROLL_FWD, + ACTION_KBD_SCROLL_BACK, #ifdef HAVE_TOUCHSCREEN /* the following are helper actions for touchscreen targets, diff --git a/apps/keymaps/keymap-e200.c b/apps/keymaps/keymap-e200.c index 538cd7c..f78fedb 100644 --- a/apps/keymaps/keymap-e200.c +++ b/apps/keymaps/keymap-e200.c @@ -254,10 +254,10 @@ static const struct button_mapping button_context_keyboard[] = { { ACTION_KBD_CURSOR_RIGHT, BUTTON_REC|BUTTON_RIGHT, BUTTON_NONE }, { ACTION_KBD_CURSOR_RIGHT, BUTTON_REC|BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_KBD_UP, BUTTON_SCROLL_BACK, BUTTON_NONE }, - { ACTION_KBD_UP, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_KBD_DOWN, BUTTON_SCROLL_FWD, BUTTON_NONE }, - { ACTION_KBD_DOWN, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_SCROLL_BACK, BUTTON_SCROLL_BACK, BUTTON_NONE }, + { ACTION_KBD_SCROLL_BACK, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_SCROLL_FWD, BUTTON_SCROLL_FWD, BUTTON_NONE }, + { ACTION_KBD_SCROLL_FWD, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_KBD_PAGE_FLIP, BUTTON_REC|BUTTON_SELECT, BUTTON_REC }, { ACTION_KBD_BACKSPACE, BUTTON_DOWN, BUTTON_NONE }, { ACTION_KBD_BACKSPACE, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, diff --git a/apps/keymaps/keymap-fuze.c b/apps/keymaps/keymap-fuze.c index e829bef..4df8114 100644 --- a/apps/keymaps/keymap-fuze.c +++ b/apps/keymaps/keymap-fuze.c @@ -256,10 +256,10 @@ static const struct button_mapping button_context_keyboard[] = { { ACTION_KBD_CURSOR_RIGHT, BUTTON_HOME|BUTTON_RIGHT, BUTTON_NONE }, { ACTION_KBD_CURSOR_RIGHT, BUTTON_HOME|BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_KBD_UP, BUTTON_SCROLL_BACK, BUTTON_NONE }, - { ACTION_KBD_UP, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_KBD_DOWN, BUTTON_SCROLL_FWD, BUTTON_NONE }, - { ACTION_KBD_DOWN, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_SCROLL_BACK, BUTTON_SCROLL_BACK, BUTTON_NONE }, + { ACTION_KBD_SCROLL_BACK, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_SCROLL_FWD, BUTTON_SCROLL_FWD, BUTTON_NONE }, + { ACTION_KBD_SCROLL_FWD, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_KBD_PAGE_FLIP, BUTTON_HOME|BUTTON_SELECT, BUTTON_HOME }, { ACTION_KBD_BACKSPACE, BUTTON_DOWN, BUTTON_NONE }, { ACTION_KBD_BACKSPACE, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE }, diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c index a438926..44920b4 100644 --- a/apps/keymaps/keymap-ipod.c +++ b/apps/keymaps/keymap-ipod.c @@ -160,13 +160,14 @@ static const struct button_mapping button_context_keyboard[] = { { ACTION_KBD_RIGHT, BUTTON_RIGHT, BUTTON_NONE }, { ACTION_KBD_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_KBD_SELECT, BUTTON_SELECT, BUTTON_NONE }, - { ACTION_KBD_DONE, BUTTON_PLAY, BUTTON_NONE }, - { ACTION_KBD_ABORT, BUTTON_MENU|BUTTON_REL, BUTTON_MENU }, - { ACTION_KBD_UP, BUTTON_SCROLL_BACK, BUTTON_NONE }, - { ACTION_KBD_UP, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_KBD_DOWN, BUTTON_SCROLL_FWD, BUTTON_NONE }, - { ACTION_KBD_DOWN, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE }, - { ACTION_KBD_MORSE_INPUT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU }, + { ACTION_KBD_DONE, BUTTON_PLAY|BUTTON_REL, BUTTON_NONE }, + { ACTION_KBD_ABORT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_SCROLL_BACK, BUTTON_SCROLL_BACK, BUTTON_NONE }, + { ACTION_KBD_SCROLL_BACK, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_SCROLL_FWD, BUTTON_SCROLL_FWD, BUTTON_NONE }, + { ACTION_KBD_SCROLL_FWD, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_BACKSPACE, BUTTON_MENU, BUTTON_NONE }, + { ACTION_KBD_BACKSPACE, BUTTON_MENU|BUTTON_REPEAT, BUTTON_NONE }, { ACTION_KBD_MORSE_SELECT, BUTTON_SELECT|BUTTON_REL, BUTTON_NONE }, LAST_ITEM_IN_LIST }; /* button_context_keyboard */ diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 0778ab7..4d86bb8 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -13030,6 +13030,118 @@ + id: LANG_KBD_MODE + desc: in settings.general.system + user: core + + *: "Keyboard Mode" + + + *: "Keyboard Mode" + + + *: "Keyboard Mode" + + + + id: LANG_KBD_MODE_STANDARD + desc: in settings.general.system + user: core + + *: "Standard" + + + *: "Standard" + + + *: "Standard" + + + + id: LANG_KBD_MODE_MORSE + desc: in settings.general.system + user: core + + *: "Morse" + + + *: "Morse" + + + *: "Morse" + + + + id: LANG_KBD_MODE_KEEP_ROLLIN + desc: in settings.general.system + user: core + + *: "Keep Rollin" + + + *: "Keep Rollin" + + + *: "Keep Rollin" + + + + id: LANG_KBD_MODE_SCROLL_1D + desc: in settings.general.system + user: core + + *: "Scroll 1D" + + + *: "Scroll 1D" + + + *: "Scroll won dee" + + + + id: LANG_KBD_MODE_ROW_COL + desc: in settings.general.system + user: core + + *: "Row-Column" + + + *: "Row-Column" + + + *: "Row Colum" + + + + id: LANG_KBD_MODE_SIDEWAYS + desc: in settings.general.system + user: core + + *: "Sideways" + + + *: "Sideways" + + + *: "Sideways" + + + + id: LANG_WHEEL_SPEED + desc: in settings.general.system + user: core + + *: "Wheel Speed" + + + *: "Wheel Speed" + + + *: "Wheel Speed" + + + id: LANG_USE_SHORTCUTS_INSTEAD_OF_QS desc: in settings_menu. user: core diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 95423a2..948bf41 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -301,8 +301,8 @@ MENUITEM_SETTING(usb_keypad_mode, &global_settings.usb_keypad_mode, NULL); MENUITEM_SETTING(usb_skip_first_drive, &global_settings.usb_skip_first_drive, NULL); #endif -#ifdef HAVE_MORSE_INPUT -MENUITEM_SETTING(morse_input, &global_settings.morse_input, NULL); +#if defined(HAVE_MORSE_INPUT) || defined(HAVE_SCROLLWHEEL) +MENUITEM_SETTING(keyboard_mode, &global_settings.keyboard_mode, NULL); #endif #ifdef HAVE_BUTTON_LIGHT @@ -333,9 +333,11 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM), #ifdef HAVE_QUICKSCREEN &shortcuts_replaces_quickscreen, #endif -#ifdef HAVE_MORSE_INPUT - &morse_input, -#endif + + #if defined(HAVE_MORSE_INPUT) || defined(HAVE_SCROLLWHEEL) + &keyboard_mode, + #endif + #if CONFIG_CODEC == MAS3507D &line_in, #endif diff --git a/apps/recorder/keyboard.c b/apps/recorder/keyboard.c index a6c015a..2129a59 100644 --- a/apps/recorder/keyboard.c +++ b/apps/recorder/keyboard.c @@ -18,6 +18,7 @@ * KIND, either express or implied. * ****************************************************************************/ +#include #include "kernel.h" #include "system.h" #include "string-extra.h" @@ -43,6 +44,8 @@ #define O_BINARY 0 #endif +/* define this if you want selected row inversed instead of underlined */ +#define KBD_INVERSE_ROW #define DEFAULT_MARGIN 6 #define KBD_BUF_SIZE 500 @@ -53,6 +56,14 @@ ((s) == SCREEN_MAIN && MIN_GRID_SIZE > (x) ? MIN_GRID_SIZE: (x)) #endif +#ifndef BUTTONBAR_HEIGHT +#define BUTTONBAR_HEIGHT 0 +#endif + +#define PRED_TEXT +#define MAX_DICT 50000 +#define MAX_DICT_WORD 50 + #if (CONFIG_KEYPAD == IRIVER_H100_PAD) \ || (CONFIG_KEYPAD == IRIVER_H300_PAD) \ || (CONFIG_KEYPAD == IPOD_1G2G_PAD) \ @@ -63,48 +74,70 @@ || (CONFIG_KEYPAD == GIGABEAT_S_PAD) \ || (CONFIG_KEYPAD == MROBE100_PAD) \ || (CONFIG_KEYPAD == SANSA_E200_PAD) \ + || (CONFIG_KEYPAD == SANSA_FUZE_PAD) \ || (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) \ || (CONFIG_KEYPAD == PHILIPS_HDD6330_PAD) \ || (CONFIG_KEYPAD == PHILIPS_SA9200_PAD) \ || (CONFIG_KEYPAD == PBELL_VIBE500_PAD) \ || (CONFIG_KEYPAD == SANSA_CONNECT_PAD) -/* certain key combos toggle input mode between keyboard input and Morse input */ +/* certain key combos change keyboard entry modes */ #define KBD_TOGGLE_INPUT #endif -#define CHANGED_PICKER 1 -#define CHANGED_CURSOR 2 -#define CHANGED_TEXT 3 +/* stored as {line_len;chars....;line_len;chars....;0xFEFF} */ +unsigned short kbd_buf[KBD_BUF_SIZE]; struct keyboard_parameters { - unsigned short kbd_buf[KBD_BUF_SIZE]; - unsigned short max_line_len; - int default_lines; + int layout_width; + int layout_lines; int last_k; int last_i; int font_w; int font_h; int text_w; - int curfont; int main_y; #ifdef HAVE_MORSE_INPUT int old_main_y; #endif - int max_chars; - int max_chars_text; - int lines; - int pages; + int window_width; + int window_height; int keyboard_margin; int curpos; - int leftpos; - int page; int x; int y; bool line_edit; #ifdef HAVE_TOUCHSCREEN bool show_buttons; + int button_h; +#endif +}; + +enum { KBD_MODE_STANDARD=0, +#ifdef HAVE_SCROLLWHEEL + KBD_MODE_SIDEWAYS, + KBD_MODE_KEEP_ROLLIN, + KBD_MODE_SCROLL_1D, + KBD_MODE_ROWCOL, +#endif +#ifdef HAVE_MORSE_INPUT + KBD_MODE_MORSE, +#endif + KBD_MODE_END +}; + +char *mode_labels[] = +{ ID2P(LANG_KBD_MODE_STANDARD), +#ifdef HAVE_SCROLLWHEEL + ID2P(LANG_KBD_MODE_SIDEWAYS), + ID2P(LANG_KBD_MODE_KEEP_ROLLIN), + ID2P(LANG_KBD_MODE_SCROLL_1D), + ID2P(LANG_KBD_MODE_ROW_COL), +#endif +#ifdef HAVE_MORSE_INPUT + ID2P(LANG_KBD_MODE_MORSE), #endif + "Bad Mode!" }; struct edit_state @@ -117,16 +150,27 @@ struct edit_state bool hangul; unsigned short hlead, hvowel, htail; #ifdef HAVE_MORSE_INPUT - bool morse_mode; bool morse_reading; unsigned char morse_code; int morse_tick; #endif - int changed; +#if defined (HAVE_MORSE_INPUT) || defined (HAVE_SCROLLWHEEL) + int keyboard_mode; +#endif +#ifdef HAVE_SCROLLWHEEL + int prev_button; + bool row; +#endif +#ifdef PRED_TEXT + char pred_word[MAX_DICT_WORD+1]; + int pred_input_len; +#endif }; static struct keyboard_parameters kbd_param[NB_SCREENS]; static bool kbd_loaded = false; +static bool kbd_uifont = false; + #ifdef HAVE_MORSE_INPUT /* FIXME: We should put this to a configuration file. */ @@ -139,12 +183,71 @@ static const unsigned char morse_codes[] = { 0x73,0x55,0x4c,0x61,0x5a,0x80 }; #endif +static void kbd_calc_params(struct keyboard_parameters *pm, + struct screen *sc, struct edit_state *state); +static void kbd_draw_picker(struct keyboard_parameters *pm, + struct screen *sc, struct edit_state *state); +static void kbd_draw_edit_line(struct keyboard_parameters *pm, + struct screen *sc, struct edit_state *state); +static void kbd_inschar(struct edit_state *state, unsigned short ch); +#ifdef HAVE_TOUCHSCREEN +static void kbd_draw_buttons(struct keyboard_parameters *pm, struct screen *sc); +static int keyboard_touchscreen(struct keyboard_parameters *pm, + struct screen *sc, struct edit_state *state); +#endif +static void kbd_delchar(struct edit_state *state); + +#ifdef HAVE_MORSE_INPUT +static void kbd_morse_select(struct edit_state *state); +#endif /* HAVE_MORSE_INPUT */ +#ifdef HAVE_SCROLLWHEEL +static void kbd_scroll_fwd( struct edit_state *state, + struct keyboard_parameters *pm); +static void kbd_scroll_back(struct edit_state *state, + struct keyboard_parameters *pm); +#endif +#ifdef PRED_TEXT +static void kbd_learn_text(char *input); + +static void kbd_load_predicted(void); + +static void kbd_save_predicted(void); + +static void kbd_draw_predicted(struct keyboard_parameters *pm, + struct screen *sc, struct edit_state *state); +static void kbd_insert_predicted(struct edit_state *state); +#endif +static void kbd_picker_right( struct edit_state *state, + struct keyboard_parameters *pm ); + +static void kbd_right( struct edit_state *state, + struct keyboard_parameters *pm ); +static void kbd_picker_left( struct edit_state *state, + struct keyboard_parameters *pm ); +static void kbd_left( struct edit_state *state, + struct keyboard_parameters *pm ); +static void kbd_down(struct edit_state *state, + struct keyboard_parameters *pm); +static void kbd_up (struct edit_state *state, + struct keyboard_parameters *pm); +static void kbd_cursor_right(struct edit_state *state); + +static void kbd_cursor_left(struct edit_state *state); + +static void kbd_backspace(struct edit_state *state, + struct keyboard_parameters *pm); +static void kbd_insert_current_char(struct edit_state *state, + struct keyboard_parameters *pm); +static void kbd_select(struct edit_state *state, + struct keyboard_parameters *pm); +static void kbd_none(struct edit_state *state); + /* Loads a custom keyboard into memory call with NULL to reset keyboard */ int load_kbd(unsigned char* filename) { int fd; - int i, line_len, max_line_len; + int i, line_len, layout_width, layout_lines=1; unsigned char buf[4]; unsigned short *pbuf; @@ -158,9 +261,9 @@ int load_kbd(unsigned char* filename) if (fd < 0) return 1; - pbuf = kbd_param[0].kbd_buf; + pbuf = kbd_buf; line_len = 0; - max_line_len = 1; + layout_width = 1; i = 1; while (read(fd, buf, 1) == 1 && i < KBD_BUF_SIZE-1) { @@ -191,11 +294,12 @@ int load_kbd(unsigned char* filename) i++; if (ch == '\n') { - if (max_line_len < line_len) - max_line_len = line_len; + if (layout_width < line_len) + layout_width = line_len; *pbuf = line_len; pbuf += line_len + 1; line_len = 0; + layout_lines++; } else pbuf[++line_len] = ch; @@ -203,10 +307,9 @@ int load_kbd(unsigned char* filename) } close(fd); - kbd_loaded = true; - if (max_line_len < line_len) - max_line_len = line_len; + if (layout_width < line_len) + layout_width = line_len; if (i == 1 || line_len != 0) /* ignore last empty line */ { *pbuf = line_len; @@ -214,19 +317,20 @@ int load_kbd(unsigned char* filename) } *pbuf = 0xFEFF; /* mark end of characters */ i++; + FOR_NB_SCREENS(l) { struct keyboard_parameters *pm = &kbd_param[l]; -#if NB_SCREENS > 1 - if (l > 0) - memcpy(pm->kbd_buf, kbd_param[0].kbd_buf, i*sizeof(unsigned short)); -#endif + /* initialize parameters */ - pm->x = pm->y = pm->page = 0; - pm->default_lines = 0; - pm->max_line_len = max_line_len; + pm->x = pm->y = 0; + pm->layout_width = layout_width; + pm->layout_lines = layout_lines; } + kbd_loaded = true; + kbd_uifont = true; + return 0; } @@ -261,7 +365,6 @@ static void kbd_inschar(struct edit_state *state, unsigned short ch) memmove(utf8 + j, utf8, len - i + 1); memcpy(utf8, tmp, j); state->editpos++; - state->changed = CHANGED_TEXT; } } @@ -278,61 +381,594 @@ static void kbd_delchar(struct edit_state *state) utf8 = state->text + i; j = utf8seek(utf8, 1); memmove(utf8, utf8 + j, len - i - j + 1); - state->changed = CHANGED_TEXT; } } /* Lookup k value based on state of param (pm) */ static unsigned short get_kbd_ch(struct keyboard_parameters *pm, int x, int y) { - int i = 0, k = pm->page*pm->lines + y, n; + int i = 0, k = y, n; unsigned short *pbuf; + if (k >= pm->last_k) { i = pm->last_i; k -= pm->last_k; } - for (pbuf = &pm->kbd_buf[i]; (i = *pbuf) != 0xFEFF; pbuf += i + 1) + for (pbuf = &kbd_buf[i]; (i = *pbuf) != 0xFEFF; pbuf += i + 1) { - n = i ? (i + pm->max_chars - 1) / pm->max_chars : 1; + n = i ? (i + pm->layout_width - 1) / pm->layout_width : 1; if (k < n) break; k -= n; } if (y == 0 && i != 0xFEFF) { - pm->last_k = pm->page*pm->lines - k; - pm->last_i = pbuf - pm->kbd_buf; + pm->last_k = - k; + pm->last_i = pbuf - kbd_buf; } - k = k * pm->max_chars + x; + k = k * pm->layout_width + x; return (*pbuf != 0xFEFF && k < *pbuf)? pbuf[k+1]: ' '; } -static void kbd_calc_params(struct keyboard_parameters *pm, - struct screen *sc, struct edit_state *state); -static void kbd_draw_picker(struct keyboard_parameters *pm, - struct screen *sc, struct edit_state *state); -static void kbd_draw_edit_line(struct keyboard_parameters *pm, - struct screen *sc, struct edit_state *state); -#ifdef HAVE_TOUCHSCREEN -static void kbd_draw_buttons(struct keyboard_parameters *pm, struct screen *sc); -static int keyboard_touchscreen(struct keyboard_parameters *pm, - struct screen *sc, struct edit_state *state); +#ifdef KBD_TOGGLE_INPUT +static void kbd_switch_mode ( struct edit_state *state ) +{ + int l; + (void)l; + FOR_NB_SCREENS(l) + { + kbd_param[l].line_edit = false; + kbd_param[l].x = 0; + kbd_param[l].y = 0; + } + state->keyboard_mode++; + if ( state->keyboard_mode == KBD_MODE_END ) + state->keyboard_mode = KBD_MODE_STANDARD; + splash(HZ/2,mode_labels[state->keyboard_mode-KBD_MODE_STANDARD] ); +} +#endif + +#ifdef HAVE_SCROLLWHEEL +static void kbd_scroll_fwd( struct edit_state *state, + struct keyboard_parameters *pm ) +{ + switch ( state->keyboard_mode ) + { + case KBD_MODE_ROWCOL: + if ( state->row ) + kbd_down( state, pm ); + else + kbd_picker_right( state, pm ); + break; + + case KBD_MODE_KEEP_ROLLIN: + if ( state->row == false ) + kbd_picker_right( state, pm ); + state->row = false; + break; + +#ifdef HAVE_MORSE_INPUT + case KBD_MODE_MORSE: + kbd_cursor_right( state ); + break; +#endif + + case KBD_MODE_SCROLL_1D: + kbd_picker_right( state, pm ); + break; + + case KBD_MODE_SIDEWAYS: + if ( pm->line_edit ) + kbd_cursor_right( state ); + else + kbd_picker_right( state, pm ); + break; + + case KBD_MODE_STANDARD: + default: + kbd_down( state, pm ); + break; + } +} + +static void kbd_scroll_back( struct edit_state *state, + struct keyboard_parameters *pm ) +{ + switch ( state->keyboard_mode ) + { + case KBD_MODE_ROWCOL: + if ( state->row ) + kbd_up( state, pm ); + else + kbd_picker_left( state, pm ); + break; + case KBD_MODE_KEEP_ROLLIN: + if ( state->row == false ) + { + kbd_insert_current_char( state, pm ); + pm->x = pm->y = 0; + state->row = true; + } + else + kbd_down( state, pm ); + break; + + case KBD_MODE_SCROLL_1D: + kbd_picker_left( state, pm ); + break; + +#ifdef HAVE_MORSE_INPUT + case KBD_MODE_MORSE: + kbd_cursor_left( state ); + break; +#endif + case KBD_MODE_SIDEWAYS: + if ( pm->line_edit ) + kbd_cursor_left( state ); + else + kbd_picker_left( state, pm ); + break; + + case KBD_MODE_STANDARD: + default: + kbd_up( state, pm ); + } +} #endif -static void kbd_insert_selected(struct keyboard_parameters *pm, - struct edit_state *state); -static void kbd_backspace(struct edit_state *state); -static void kbd_move_cursor(struct edit_state *state, int dir); -static void kbd_move_picker_horizontal(struct keyboard_parameters *pm, - struct edit_state *state, int dir); -static void kbd_move_picker_vertical(struct keyboard_parameters *pm, - struct edit_state *state, int dir); + +static void kbd_picker_right( struct edit_state *state, + struct keyboard_parameters *pm ) +{ + (void) state; + if (++pm->x >= pm->layout_width) + { +#ifdef HAVE_SCROLLWHEEL + switch ( state->keyboard_mode ) + { + case KBD_MODE_ROWCOL: + pm->x = pm->layout_width-1; + state->row = true; + return; + case KBD_MODE_SCROLL_1D: + kbd_down( state, pm ); + case KBD_MODE_KEEP_ROLLIN: + pm->x = 0; + return; + default: + break; + } +#endif + pm->x = 0; + } + kbd_spellchar( get_kbd_ch(pm, pm->x, pm->y) ); +} + +static void kbd_right( struct edit_state *state, + struct keyboard_parameters *pm ) +{ +#ifdef HAVE_SCROLLWHEEL + switch ( state->keyboard_mode ) + { + case KBD_MODE_STANDARD: + if ( pm->line_edit ) + kbd_cursor_right( state ); + else + kbd_picker_right( state, pm ); + return; + + case KBD_MODE_SIDEWAYS: + kbd_down( state, pm ); + return; + + case KBD_MODE_KEEP_ROLLIN: + case KBD_MODE_SCROLL_1D: + case KBD_MODE_ROWCOL: +#ifdef HAVE_MORSE_INPUT + case KBD_MODE_MORSE: +#endif + kbd_cursor_right( state ); + return; + default: + break; + } +#else /* (not) HAVE_SCROLLWHEEL */ + if ( pm->line_edit ) + kbd_cursor_right( state ); + else + kbd_picker_right( state, pm ); +#endif /* HAVE_SCROLLWHEEL */ +} + +static void kbd_picker_left( struct edit_state *state, + struct keyboard_parameters *pm ) +{ + (void) state; + if (--pm->x < 0) + { +#ifdef HAVE_SCROLLWHEEL + switch ( state->keyboard_mode ) + { + case KBD_MODE_ROWCOL: + pm->x = 0; + state->row = true; + return; + case KBD_MODE_SCROLL_1D: + kbd_up( state, pm ); + case KBD_MODE_KEEP_ROLLIN: + state->row = true; + pm->x = pm->layout_width - 1; + return; + default: + break; + } +#endif + pm->x = pm->layout_width - 1; + } + kbd_spellchar( get_kbd_ch(pm, pm->x, pm->y) ); +} + +static void kbd_left( struct edit_state *state, + struct keyboard_parameters *pm ) +{ +#ifdef HAVE_SCROLLWHEEL + switch ( state->keyboard_mode ) + { + case KBD_MODE_STANDARD: + if ( pm->line_edit ) + kbd_cursor_left( state ); + else + kbd_picker_left( state, pm ); + return; + + case KBD_MODE_SIDEWAYS: + kbd_up( state, pm ); + return; + case KBD_MODE_KEEP_ROLLIN: + case KBD_MODE_SCROLL_1D: + case KBD_MODE_ROWCOL: +#ifdef HAVE_MORSE_INPUT + case KBD_MODE_MORSE: +#endif + kbd_cursor_left( state ); + return; + default: + return; + } +#else /* (not) HAVE_SCROLLWHEEL */ + if ( pm->line_edit ) + kbd_cursor_left( state ); + else + kbd_picker_left( state, pm ); +#endif /* HAVE_SCROLLWHEEL */ + +} + +static void kbd_down( struct edit_state *state, + struct keyboard_parameters *pm ) +{ +#ifdef HAVE_SCROLLWHEEL + if ( state->keyboard_mode == KBD_MODE_KEEP_ROLLIN || + state->keyboard_mode == KBD_MODE_SCROLL_1D || + state->keyboard_mode == KBD_MODE_ROWCOL ) + { + if (++pm->y >= pm->layout_lines) + { + pm->y = 0; + } + return; + } +#endif +#ifdef HAVE_MORSE_INPUT + if (state->keyboard_mode == KBD_MODE_MORSE) + { + pm->line_edit = !pm->line_edit; + return; + } +#endif /* HAVE_MORSE_INPUT */ + + if (pm->line_edit) + { + pm->y = 0; + pm->line_edit = false; + } + else if (++pm->y >= pm->layout_lines) + { + pm->line_edit = true; + } + if (!pm->line_edit) + { + kbd_spellchar( get_kbd_ch(pm, pm->x, pm->y) ); + } + return; +} + +static void kbd_up ( struct edit_state *state, + struct keyboard_parameters *pm ) +{ +#ifdef HAVE_SCROLLWHEEL + if ( state->keyboard_mode == KBD_MODE_KEEP_ROLLIN || + state->keyboard_mode == KBD_MODE_SCROLL_1D || + state->keyboard_mode == KBD_MODE_ROWCOL ) + { + if (--pm->y < 0) + { + pm->y = pm->layout_lines - 1; + } + return; + } +#endif +#ifdef HAVE_MORSE_INPUT + if (state->keyboard_mode == KBD_MODE_MORSE) + { + pm->line_edit = !pm->line_edit; + return; + } +#endif /* HAVE_MORSE_INPUT */ + if (pm->line_edit) + { + pm->y = pm->layout_lines - 1; + pm->line_edit = false; + } + else if (--pm->y < 0) + { + pm->line_edit = true; + } + if (!pm->line_edit) + kbd_spellchar( get_kbd_ch(pm, pm->x, pm->y) ); +} + +static void kbd_cursor_right( struct edit_state *state ) +{ + state->hangul = false; + + if (state->editpos < state->len_utf8) + { + int c = utf8seek(state->text, ++state->editpos); + kbd_spellchar(state->text[c]); + return; + } +#ifdef PRED_TEXT + if( state->pred_word[0] ) + { + kbd_insert_predicted( state ); + return; + } +#else + state->editpos = 0; +#endif +} + +static void kbd_cursor_left( struct edit_state *state ) +{ + state->hangul = false; + + if (state->editpos > 0) + { + int c = utf8seek(state->text, --state->editpos); + kbd_spellchar(state->text[c]); + } + else + state->editpos = state->len_utf8; +} + +static void kbd_backspace( struct edit_state *state, + struct keyboard_parameters *pm) +{ + unsigned short ch; + +#ifdef HAVE_SCROLLWHEEL + /* zero picker column, zero picker row, then backspace */ + if ( state->keyboard_mode == KBD_MODE_KEEP_ROLLIN ) + { + if ( pm->x || pm->y ) + { + pm->x = 0; + pm->y = 0; + return; + } + } +#endif + (void)pm; + if (state->hangul) + { + if (state->htail) + state->htail = 0; + else if (state->hvowel) + state->hvowel = 0; + else + state->hangul = false; + } + + kbd_delchar(state); + + if (state->hangul) + { + if (state->hvowel) + ch = hangul_join(state->hlead, state->hvowel, state->htail); + else + ch = state->hlead; + kbd_inschar(state, ch); + } + + if (global_settings.talk_menu) /* voice UI? */ + talk_spell(state->text, false); /* speak revised text */ +} + +static void kbd_insert_current_char( struct edit_state *state, + struct keyboard_parameters *pm ) +{ + + /* inserts the selected char */ + /* find input char */ + unsigned short ch; + ch = get_kbd_ch(pm, pm->x, pm->y); + + /* check for hangul input */ + if (ch >= 0x3131 && ch <= 0x3163) + { + unsigned short tmp; + + if (!state->hangul) + { + state->hlead = state->hvowel = state->htail = 0; + state->hangul = true; + } + + if (!state->hvowel) + { + state->hvowel = ch; + } + else if (!state->htail) + { + state->htail = ch; + } + else + { + /* previous hangul complete */ + /* check whether tail is actually lead of next char */ + tmp = hangul_join(state->htail, ch, 0); + + if (tmp != 0xfffd) + { + tmp = hangul_join(state->hlead, state->hvowel, 0); + kbd_delchar(state); + kbd_inschar(state, tmp); + /* insert dummy char */ + kbd_inschar(state, ' '); + state->hlead = state->htail; + state->hvowel = ch; + state->htail = 0; + } + else + { + state->hvowel = state->htail = 0; + state->hlead = ch; + } + } + + /* combine into hangul */ + tmp = hangul_join(state->hlead, state->hvowel, state->htail); + + if (tmp != 0xfffd) + { + kbd_delchar(state); + ch = tmp; + } + else + { + state->hvowel = state->htail = 0; + state->hlead = ch; + } + } + else + { + state->hangul = false; + } + + /* insert char */ + kbd_inschar(state, ch); + + if (global_settings.talk_menu) /* voice UI? */ + talk_spell(state->text, false); /* speak revised text */ +} + +static void kbd_select( struct edit_state *state, + struct keyboard_parameters *pm ) +{ +#ifdef HAVE_SCROLLWHEEL + if ( state->keyboard_mode == KBD_MODE_ROWCOL ) + { + if ( state->row ) + { + state->row = false; + return; + } + else + { + kbd_insert_current_char( state, pm ); + return; + } + } + if ( state->keyboard_mode == KBD_MODE_KEEP_ROLLIN ) + { + state->row = false; + kbd_insert_current_char( state, pm ); + return; + } +#endif /* HAVE_SCROLLWHEEL */ + if ( pm->line_edit ) + { + kbd_backspace( state, pm ); + return; + } +#ifdef HAVE_MORSE_INPUT + if (state->keyboard_mode == KBD_MODE_MORSE) + { + state->morse_tick = current_tick; + + if (!state->morse_reading) + { + logf("Morse char start:\n"); + state->morse_reading = true; + state->morse_code = 1; + } + } + else +#endif /* HAVE_MORSE_INPUT */ + kbd_insert_current_char( state, pm ); +} + +#ifdef HAVE_MORSE_INPUT +static void kbd_morse_select( struct edit_state *state ) +{ + if (state->keyboard_mode == KBD_MODE_MORSE && state->morse_reading) + { + state->morse_code <<= 1; + if ((current_tick - state->morse_tick) > HZ/5) + state->morse_code |= 0x01; + } +} +#endif /* HAVE_MORSE_INPUT */ + +static void kbd_none( struct edit_state *state ) +{ + (void) state; +#ifdef HAVE_MORSE_INPUT + if (state->morse_reading) + { + int j; + logf("Morse: 0x%02x", state->morse_code); + state->morse_reading = false; + + for (j = 0; morse_alphabets[j] != '\0'; j++) + { + if (morse_codes[j] == state->morse_code) + break; + } + + if (morse_alphabets[j] == '\0') + { + logf("Morse code not found"); + return; + } + + /* turn off hangul input */ + state->hangul = false; + kbd_inschar(state, morse_alphabets[j]); + + if (global_settings.talk_menu) /* voice UI? */ + talk_spell(state->text, false); /* speak revised text */ + } +#endif /* HAVE_MORSE_INPUT */ +} int kbd_input(char* text, int buflen) { bool done = false; struct keyboard_parameters * const param = kbd_param; struct edit_state state; - unsigned short ch; + int l; /* screen loop variable */ + (void)l; int ret = 0; /* assume success */ FOR_NB_SCREENS(l) { @@ -351,92 +987,96 @@ int kbd_input(char* text, int buflen) /* initialize state */ state.text = text; state.buflen = buflen; +#ifdef HAVE_SCROLLWHEEL + state.prev_button = BUTTON_NONE; + state.row = true; +#endif +#ifdef PRED_TEXT + kbd_load_predicted(); + state.pred_word[0] = 0; +#endif /* Initial edit position is after last character */ state.editpos = utf8length(state.text); state.cur_blink = true; +#if defined (HAVE_MORSE_INPUT) || defined (HAVE_SCROLLWHEEL) + state.keyboard_mode = global_settings.keyboard_mode; +#endif #ifdef HAVE_MORSE_INPUT - state.morse_mode = global_settings.morse_input; state.morse_reading = false; #endif state.hangul = false; - state.changed = 0; if (!kbd_loaded) { - /* Copy default keyboard to buffer */ - FOR_NB_SCREENS(l) - { - struct keyboard_parameters *pm = ¶m[l]; - unsigned short *pbuf; - const unsigned char *p; - int len = 0; + unsigned short *pbuf; + const unsigned char *p; + int len = 0; #if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 - struct screen *sc = &screens[l]; + p = "ABCDEFG abcdefg !?\" @#$%+'\n" + "HIJKLMN hijklmn 789 &_()-`\n" + "OPQRSTU opqrstu 456 §|{}/<\n" + "VWXYZ., vwxyz.,0123 ~=[]*>\n" + "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n" + "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n" + "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n" + "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;"; + + param[0].layout_lines = 8; + param[0].layout_width = 26; + +#else /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */ + p = "ABCDEFG !?\" @#$%+'\n" + "HIJKLMN 789 &_()-`\n" + "OPQRSTU 456 §|{}/<\n" + "VWXYZ.,0123 ~=[]*>\n" + + "abcdefg ¢£¤¥¦§©®¬\n" + "hijklmn «»°ºª¹²³¶\n" + "opqrstu ¯±×÷¡¿µ·¨\n" + "vwxyz., :;¼½¾ \n" + + "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n" + "àáâãäåæ ìíîï èéêë\n" + "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n" + "òóôõöø çðþýÿ ùúûü"; + + param[0].layout_lines = 4; + param[0].layout_width = 18; +#endif - if (sc->getwidth() >= 160 && sc->getheight() >= 96) + pbuf = kbd_buf; + while (*p) + { + p = utf8decode(p, &pbuf[len+1]); + if (pbuf[len+1] == '\n') { - p = "ABCDEFG abcdefg !?\" @#$%+'\n" - "HIJKLMN hijklmn 789 &_()-`\n" - "OPQRSTU opqrstu 456 §|{}/<\n" - "VWXYZ., vwxyz.,0123 ~=[]*>\n" - "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n" - "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n" - "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n" - "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;"; - - pm->default_lines = 8; - pm->max_line_len = 26; + *pbuf = len; + pbuf += len+1; + len = 0; } else -#endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */ - { - p = "ABCDEFG !?\" @#$%+'\n" - "HIJKLMN 789 &_()-`\n" - "OPQRSTU 456 §|{}/<\n" - "VWXYZ.,0123 ~=[]*>\n" - - "abcdefg ¢£¤¥¦§©®¬\n" - "hijklmn «»°ºª¹²³¶\n" - "opqrstu ¯±×÷¡¿µ·¨\n" - "vwxyz., :;¼½¾ \n" - - "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n" - "àáâãäåæ ìíîï èéêë\n" - "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n" - "òóôõöø çðþýÿ ùúûü"; - - pm->default_lines = 4; - pm->max_line_len = 18; - } - - pbuf = pm->kbd_buf; - while (*p) - { - p = utf8decode(p, &pbuf[len+1]); - if (pbuf[len+1] == '\n') - { - *pbuf = len; - pbuf += len+1; - len = 0; - } - else - len++; - } - *pbuf = len; - pbuf[len+1] = 0xFEFF; /* mark end of characters */ - - /* initialize parameters */ - pm->x = pm->y = pm->page = 0; + len++; } - kbd_loaded = true; + *pbuf = len; + pbuf[len+1] = 0xFEFF; /* mark end of characters */ } + kbd_loaded = true; FOR_NB_SCREENS(l) { struct keyboard_parameters *pm = ¶m[l]; struct screen *sc = &screens[l]; + + pm->x = pm->y = 0; + pm->line_edit = false; + pm->layout_lines = param[0].layout_lines; + pm->layout_width = param[0].layout_width; kbd_calc_params(pm, sc, &state); +#ifdef HAVE_SCROLLWHEEL + pm->x = pm->y = 0; + pm->line_edit = false; +#endif } if (global_settings.talk_menu) /* voice UI? */ @@ -448,12 +1088,8 @@ int kbd_input(char* text, int buflen) action occurred - pointers save a lot of space over array notation when accessing the same array element countless times */ int button; -#if NB_SCREENS > 1 - int button_screen; -#else - const int button_screen = 0; -#endif struct keyboard_parameters *pm; + struct screen *sc; state.len_utf8 = utf8length(state.text); @@ -470,6 +1106,10 @@ int kbd_input(char* text, int buflen) if (pm->show_buttons) kbd_draw_buttons(pm, sc); #endif +#ifdef PRED_TEXT + /* just the main screen */ + kbd_draw_predicted(¶m[0], &screens[0], &state); +#endif } #ifdef HAVE_BUTTONBAR @@ -483,41 +1123,29 @@ int kbd_input(char* text, int buflen) state.cur_blink = !state.cur_blink; - button = get_action( #ifdef HAVE_MORSE_INPUT - state.morse_mode? CONTEXT_MORSE_INPUT: -#endif - CONTEXT_KEYBOARD, HZ/2); -#if NB_SCREENS > 1 - button_screen = (get_action_statuscode(NULL) & ACTION_REMOTE) ? 1 : 0; + button = get_action( state.keyboard_mode == KBD_MODE_MORSE ? + CONTEXT_MORSE_INPUT: CONTEXT_KEYBOARD, HZ/2 ); +#else + button = get_action( CONTEXT_KEYBOARD, HZ/2 ); #endif - pm = ¶m[button_screen]; + + pm = ¶m[0]; + sc = &screens[0]; #ifdef HAVE_TOUCHSCREEN if (button == ACTION_TOUCHSCREEN) - { - struct screen *sc = &screens[button_screen]; button = keyboard_touchscreen(pm, sc, &state); - } #endif - - /* Remap some buttons to allow to move - * cursor in line edit mode and morse mode. */ - if (pm->line_edit -#ifdef HAVE_MORSE_INPUT - || state.morse_mode -#endif /* HAVE_MORSE_INPUT */ - ) - { - if (button == ACTION_KBD_LEFT) - button = ACTION_KBD_CURSOR_LEFT; - if (button == ACTION_KBD_RIGHT) - button = ACTION_KBD_CURSOR_RIGHT; - } - switch ( button ) { case ACTION_KBD_DONE: /* accepts what was entered and continues */ +#ifdef PRED_TEXT + /* learn if cursor at end of line */ + if( state.editpos == state.len_utf8 ) + kbd_learn_text( state.text ); + kbd_save_predicted(); +#endif ret = 0; done = true; break; @@ -526,118 +1154,60 @@ int kbd_input(char* text, int buflen) ret = -1; done = true; break; +#ifdef HAVE_SCROLLWHEEL + case ACTION_KBD_SCROLL_FWD: + kbd_scroll_fwd(&state, pm); + break; - case ACTION_KBD_PAGE_FLIP: -#ifdef HAVE_MORSE_INPUT - if (state.morse_mode) - break; + case ACTION_KBD_SCROLL_BACK: + kbd_scroll_back(&state, pm); + break; #endif - if (++pm->page >= pm->pages) - pm->page = 0; - - state.changed = CHANGED_PICKER; +#ifdef KBD_TOGGLE_INPUT + case ACTION_KBD_MORSE_INPUT: + kbd_switch_mode(&state); + break; +#endif +#ifdef HAVE_MORSE_INPUT + case ACTION_KBD_MORSE_SELECT: + kbd_morse_select(&state); break; +#endif /* HAVE_MORSE_INPUT */ case ACTION_KBD_RIGHT: - kbd_move_picker_horizontal(pm, &state, 1); + kbd_right(&state, pm); break; case ACTION_KBD_LEFT: - kbd_move_picker_horizontal(pm, &state, -1); + kbd_left(&state, pm); break; case ACTION_KBD_DOWN: - kbd_move_picker_vertical(pm, &state, 1); + kbd_down(&state, pm); break; case ACTION_KBD_UP: - kbd_move_picker_vertical(pm, &state, -1); - break; - -#ifdef HAVE_MORSE_INPUT -#ifdef KBD_TOGGLE_INPUT - case ACTION_KBD_MORSE_INPUT: - state.morse_mode = !state.morse_mode; - state.changed = CHANGED_PICKER; - - FOR_NB_SCREENS(l) - { - struct keyboard_parameters *pm = ¶m[l]; - int y = pm->main_y; - pm->main_y = pm->old_main_y; - pm->old_main_y = y; - } - break; -#endif /* KBD_TOGGLE_INPUT */ - - case ACTION_KBD_MORSE_SELECT: - if (state.morse_mode && state.morse_reading) - { - state.morse_code <<= 1; - if ((current_tick - state.morse_tick) > HZ/5) - state.morse_code |= 0x01; - } + kbd_up(&state, pm); break; -#endif /* HAVE_MORSE_INPUT */ case ACTION_KBD_SELECT: - /* select doubles as backspace in line_edit */ - if (pm->line_edit) - kbd_backspace(&state); - else -#ifdef HAVE_MORSE_INPUT - if (state.morse_mode) - { - state.morse_tick = current_tick; - - if (!state.morse_reading) - { - state.morse_reading = true; - state.morse_code = 1; - } - } - else -#endif /* HAVE_MORSE_INPUT */ - kbd_insert_selected(pm, &state); + kbd_select(&state, pm); break; case ACTION_KBD_BACKSPACE: - kbd_backspace(&state); + kbd_backspace(&state, pm); break; case ACTION_KBD_CURSOR_RIGHT: - kbd_move_cursor(&state, 1); + kbd_cursor_right(&state); break; case ACTION_KBD_CURSOR_LEFT: - kbd_move_cursor(&state, -1); + kbd_cursor_left(&state); break; case ACTION_NONE: -#ifdef HAVE_MORSE_INPUT - if (state.morse_reading) - { - int j; - logf("Morse: 0x%02x", state.morse_code); - state.morse_reading = false; - - for (j = 0; morse_alphabets[j] != '\0'; j++) - { - if (morse_codes[j] == state.morse_code) - break ; - } - - if (morse_alphabets[j] == '\0') - { - logf("Morse code not found"); - break ; - } - - /* turn off hangul input */ - state.hangul = false; - kbd_inschar(&state, morse_alphabets[j]); - } -#endif /* HAVE_MORSE_INPUT */ + kbd_none(&state); break; default: @@ -649,38 +1219,19 @@ int kbd_input(char* text, int buflen) break; } /* end switch */ - + FOR_NB_SCREENS(l) + { + param[l].x = param[0].x; + param[l].y = param[0].y; + param[l].line_edit = param[0].line_edit; + } if (button != ACTION_NONE) { - state.cur_blink = true; - } - if (global_settings.talk_menu) /* voice UI? */ - { - if (state.changed == CHANGED_PICKER) - { - if (pm->line_edit) - { - talk_id(VOICE_EDIT, false); - } - else -#ifdef HAVE_MORSE_INPUT - /* FIXME: We should talk something like Morse mode.. */ - if (!state.morse_mode) +#ifdef HAVE_SCROLLWHEEL + state.prev_button = button; #endif - { - ch = get_kbd_ch(pm, pm->x, pm->y); - kbd_spellchar(ch); - } - } - else if (state.changed == CHANGED_CURSOR) - { - int c = utf8seek(state.text, state.editpos); - kbd_spellchar(state.text[c]); - } - else if (state.changed == CHANGED_TEXT) - talk_spell(state.text, false); /* speak revised text */ + state.cur_blink = true; } - state.changed = 0; } #ifdef HAVE_BUTTONBAR @@ -689,11 +1240,10 @@ int kbd_input(char* text, int buflen) if (ret < 0) splash(HZ/2, ID2P(LANG_CANCEL)); - -#if defined(HAVE_MORSE_INPUT) && defined(KBD_TOGGLE_INPUT) - if (global_settings.morse_input != state.morse_mode) +#if defined(HAVE_MORSE_INPUT) || defined(HAVE_SCROLLWHEEL) + if (global_settings.keyboard_mode != state.keyboard_mode) { - global_settings.morse_input = state.morse_mode; + global_settings.keyboard_mode = state.keyboard_mode; settings_save(); } #endif /* HAVE_MORSE_INPUT && KBD_TOGGLE_INPUT */ @@ -712,23 +1262,26 @@ static void kbd_calc_params(struct keyboard_parameters *pm, struct font* font; const unsigned char *p; unsigned short ch, *pbuf; - int icon_w, sc_w, sc_h, w; - int i, total_lines; + int sc_w, sc_h, w; + int i, total_lines, font_id; #ifdef HAVE_TOUCHSCREEN int button_h = 0; - bool flippage_button = false; pm->show_buttons = (sc->screen_type == SCREEN_MAIN && (touchscreen_get_mode() == TOUCHSCREEN_POINT)); #endif + if( kbd_uifont ) + font_id = sc->getuifont(); + else + font_id = FONT_SYSFIXED; + + font = font_get( font_id ); - pm->curfont = pm->default_lines ? FONT_SYSFIXED : sc->getuifont(); - font = font_get(pm->curfont); pm->font_h = font->height; /* check if FONT_UI fits the screen */ if (2*pm->font_h + 3 + BUTTONBAR_HEIGHT > sc->getheight()) { - pm->curfont = FONT_SYSFIXED; + kbd_uifont = false; font = font_get(FONT_SYSFIXED); pm->font_h = font->height; } @@ -740,7 +1293,7 @@ static void kbd_calc_params(struct keyboard_parameters *pm, * since we're going to be adding spaces, * max width is at least their width */ pm->font_w = font_get_width(font, ' '); - for (pbuf = pm->kbd_buf; *pbuf != 0xFEFF; pbuf += i) + for (pbuf = kbd_buf; *pbuf != 0xFEFF; pbuf += i) { for (i = 0; ++i <= *pbuf; ) { @@ -765,38 +1318,42 @@ static void kbd_calc_params(struct keyboard_parameters *pm, pm->font_w = GRID_SIZE(sc->screen_type, pm->font_w); #endif /* calculate how many characters to put in a row. */ - icon_w = get_icon_width(sc->screen_type); sc_w = sc->getwidth(); - if (pm->font_w < sc_w / pm->max_line_len) - pm->font_w = sc_w / pm->max_line_len; - pm->max_chars = sc_w / pm->font_w; - pm->max_chars_text = (sc_w - icon_w * 2 - 2) / pm->text_w; - if (pm->max_chars_text < 3 && icon_w > pm->text_w) - pm->max_chars_text = sc_w / pm->text_w - 2; - - /* calculate pm->pages and pm->lines */ + if (pm->font_w < sc_w / pm->layout_width) + pm->font_w = sc_w / pm->layout_width; + pm->window_width = sc_w / pm->font_w; + if ( pm->window_width > pm->layout_width ) + pm->window_width = pm->layout_width; + + /* calculate and pm->window_height */ sc_h = sc->getheight(); +#ifdef PRED_TEXT + if ( sc == &screens[0] ) + /* reserve a line for predicted text on main screen */ + sc_h -= pm->font_h; +#endif #ifdef HAVE_TOUCHSCREEN /* add space for buttons */ if (pm->show_buttons) { /* reserve place for OK/Del/Cancel buttons, use ui font for them */ button_h = GRID_SIZE(sc->screen_type, sc->getcharheight()); - sc_h -= MAX(MIN_GRID_SIZE*2, button_h); + pm->button_h = MAX(MIN_GRID_SIZE*2, button_h); + sc_h -= pm->button_h; } recalc_param: #endif - pm->lines = (sc_h - BUTTONBAR_HEIGHT) / pm->font_h - 1; + pm->window_height = (sc_h - BUTTONBAR_HEIGHT) / pm->font_h - 1; - if (pm->default_lines && pm->lines > pm->default_lines) - pm->lines = pm->default_lines; + if (pm->layout_lines && pm->window_height > pm->layout_lines) + pm->window_height = pm->layout_lines; pm->keyboard_margin = sc_h - BUTTONBAR_HEIGHT - - (pm->lines+1)*pm->font_h; + - (pm->window_height+1)*pm->font_h; - if (pm->keyboard_margin < 3 && pm->lines > 1) + if (pm->keyboard_margin < 3 && pm->window_height > 1) { - pm->lines--; + pm->window_height--; pm->keyboard_margin += pm->font_h; } @@ -804,34 +1361,24 @@ recalc_param: pm->keyboard_margin = DEFAULT_MARGIN; total_lines = 0; - for (pbuf = pm->kbd_buf; (i = *pbuf) != 0xFEFF; pbuf += i + 1) - total_lines += (i ? (i + pm->max_chars - 1) / pm->max_chars : 1); + for (pbuf = kbd_buf; (i = *pbuf) != 0xFEFF; pbuf += i + 1) + total_lines += (i ? (i + pm->layout_width - 1) / pm->layout_width : 1); + pm->layout_lines = total_lines; - pm->pages = (total_lines + pm->lines - 1) / pm->lines; - pm->lines = (total_lines + pm->pages - 1) / pm->pages; #ifdef HAVE_TOUCHSCREEN - if (pm->pages > 1 && pm->show_buttons && !flippage_button) - { - /* add space for flip page button */ - sc_h -= button_h; - flippage_button = true; - goto recalc_param; - } + pm->window_height = ( (sc_h -BUTTONBAR_HEIGHT -button_h -pm->font_h -2*pm->keyboard_margin) / + pm->font_h ); +#else + pm->window_height = ( (sc_h -BUTTONBAR_HEIGHT -pm->font_h -2*pm->keyboard_margin) / + pm->font_h ); #endif - if (pm->page >= pm->pages) - pm->x = pm->y = pm->page = 0; - pm->main_y = pm->font_h*pm->lines + pm->keyboard_margin; + pm->main_y = pm->font_h*pm->window_height + pm->keyboard_margin; pm->keyboard_margin -= pm->keyboard_margin/2; -#ifdef HAVE_TOUCHSCREEN - /* flip page button is put between piker and edit line */ - if (flippage_button) - pm->main_y += button_h; -#endif #ifdef HAVE_MORSE_INPUT pm->old_main_y = sc_h - pm->font_h - BUTTONBAR_HEIGHT; - if (state->morse_mode) + if (state->keyboard_mode == KBD_MODE_MORSE) { int y = pm->main_y; pm->main_y = pm->old_main_y; @@ -845,7 +1392,7 @@ static void kbd_draw_picker(struct keyboard_parameters *pm, { char outline[8]; #ifdef HAVE_MORSE_INPUT - if (state->morse_mode) + if (state->keyboard_mode == KBD_MODE_MORSE) { const int w = 6, h = 8; /* sysfixed font width, height */ int i, j, x, y; @@ -900,14 +1447,36 @@ static void kbd_draw_picker(struct keyboard_parameters *pm, int w, h; unsigned short ch; unsigned char *utf8; + int x_offset = 0, y_offset = 0; - sc->setfont(pm->curfont); - - for (j = 0; j < pm->lines; j++) + if(kbd_uifont) + sc->setfont(FONT_UI); + else + sc->setfont(FONT_SYSFIXED); + + if( pm->window_width < pm->layout_width ) + { + x_offset = pm->x - pm->window_width/2; + if( x_offset > pm->layout_width - pm->window_width ) + x_offset = pm->layout_width - pm->window_width; + } + if( x_offset < 0 ) + x_offset = 0; + + if( pm->window_height < pm->layout_lines ) + { + y_offset = pm->y - pm->window_height/2; + if (y_offset > pm->layout_lines - pm->window_height ) + y_offset = pm->layout_lines - pm->window_height; + } + if ( y_offset < 0 ) + y_offset = 0; + + for (j = 0; j < pm->window_height && j < pm->layout_lines; j++) { - for (i = 0; i < pm->max_chars; i++) + for (i = 0; i < pm->window_width && i < pm->layout_width; i++) { - ch = get_kbd_ch(pm, i, j); + ch = get_kbd_ch(pm, i+x_offset, j+y_offset); utf8 = utf8encode(ch, outline); *utf8 = 0; @@ -921,7 +1490,20 @@ static void kbd_draw_picker(struct keyboard_parameters *pm, { /* highlight the key that has focus */ sc->set_drawmode(DRMODE_COMPLEMENT); - sc->fillrect(pm->font_w*pm->x, pm->font_h*pm->y, +#ifdef HAVE_SCROLLWHEEL + if ( (state->keyboard_mode == KBD_MODE_ROWCOL && state->row) || + (state->keyboard_mode == KBD_MODE_KEEP_ROLLIN && state->row )) +#ifdef KBD_INVERSE_ROW + sc->fillrect(0,pm->font_h*(pm->y-y_offset), + sc->getwidth(), pm->font_h); +#else /* underline current row */ + sc->hline(0, sc->getwidth(), + pm->font_h*(pm->y+1-y_offset)); +#endif + else +#endif /* HAVE_SCROLLWHEEL */ + sc->fillrect(pm->font_w*(pm->x-x_offset), + pm->font_h*(pm->y-y_offset), pm->font_w, pm->font_h); sc->set_drawmode(DRMODE_SOLID); } @@ -931,12 +1513,11 @@ static void kbd_draw_picker(struct keyboard_parameters *pm, static void kbd_draw_edit_line(struct keyboard_parameters *pm, struct screen *sc, struct edit_state *state) { - char outline[8]; - unsigned char *utf8; - int i = 0, j = 0, icon_w, w; + int total_w, tail_w, x_offset,cursor; int sc_w = sc->getwidth(); int y = pm->main_y - pm->keyboard_margin; - int text_margin = (sc_w - pm->text_w * pm->max_chars_text) / 2; + int text_margin = 5; + int window_w = sc_w-2*text_margin; /* Clear text area one pixel above separator line so any overdraw doesn't collide */ @@ -944,76 +1525,38 @@ static void kbd_draw_edit_line(struct keyboard_parameters *pm, sc->hline(0, sc_w - 1, y); - /* write out the text */ - sc->setfont(pm->curfont); - - pm->leftpos = MAX(0, MIN(state->len_utf8, state->editpos + 2) - - pm->max_chars_text); - pm->curpos = state->editpos - pm->leftpos; - utf8 = state->text + utf8seek(state->text, pm->leftpos); - - while (*utf8 && i < pm->max_chars_text) - { - j = utf8seek(utf8, 1); - strlcpy(outline, utf8, j+1); - sc->getstringsize(outline, &w, NULL); - sc->putsxy(text_margin + i*pm->text_w + (pm->text_w-w)/2, - pm->main_y, outline); - utf8 += j; - i++; - } - - icon_w = get_icon_width(sc->screen_type); - if (pm->leftpos > 0) - { - /* Draw nicer bitmap arrow if room, else settle for "<". */ - if (text_margin >= icon_w) - { - screen_put_icon_with_offset(sc, 0, 0, - (text_margin - icon_w) / 2, - pm->main_y, Icon_Reverse_Cursor); - } - else - { - sc->getstringsize("<", &w, NULL); - sc->putsxy(text_margin - w, pm->main_y, "<"); - } - } - - if (state->len_utf8 - pm->leftpos > pm->max_chars_text) - { - /* Draw nicer bitmap arrow if room, else settle for ">". */ - if (text_margin >= icon_w) - { - screen_put_icon_with_offset(sc, 0, 0, - sc_w - (text_margin + icon_w) / 2, - pm->main_y, Icon_Cursor); - } - else - { - sc->putsxy(sc_w - text_margin, pm->main_y, ">"); - } - } - - /* cursor */ - i = text_margin + pm->curpos * pm->text_w; - + if(kbd_uifont) + sc->setfont(FONT_UI); + else + sc->setfont(FONT_SYSFIXED); + /* check length of edit line */ + sc->getstringsize(state->text, &total_w, NULL); + /* check length of line from cursor to end */ + sc->getstringsize(&state->text[utf8seek(state->text,state->editpos)], &tail_w, NULL); + + x_offset = (window_w-total_w+tail_w); + if ( total_w-tail_w < window_w ) x_offset = 0; + sc->putsxy( x_offset+text_margin,pm->main_y, state->text); + cursor = x_offset+total_w-tail_w+text_margin; if (state->cur_blink) - sc->vline(i, pm->main_y, pm->main_y + pm->font_h - 1); - + sc->vline(cursor, pm->main_y, pm->main_y + pm->font_h - 1); if (state->hangul) /* draw underbar */ - sc->hline(i - pm->text_w, i, pm->main_y + pm->font_h - 1); + sc->hline(cursor-pm->text_w, cursor, + pm->main_y + pm->font_h - 1); +#ifdef KBD_TOGGLE_INPUT if (pm->line_edit) { sc->set_drawmode(DRMODE_COMPLEMENT); sc->fillrect(0, y + 2, sc_w, pm->font_h + 2); sc->set_drawmode(DRMODE_SOLID); } +#endif } #ifdef HAVE_TOUCHSCREEN -static void kbd_draw_buttons(struct keyboard_parameters *pm, struct screen *sc) +static void kbd_draw_buttons(struct keyboard_parameters *pm, + struct screen *sc) { struct viewport vp; int button_h, text_h, text_y; @@ -1029,13 +1572,6 @@ static void kbd_draw_buttons(struct keyboard_parameters *pm, struct screen *sc) vp.width = sc_w; vp.height = button_h; /* draw buttons */ - if (pm->pages > 1) - { - /* button to flip page. */ - vp.y = pm->lines*pm->font_h; - sc->hline(0, sc_w - 1, 0); - sc->putsxy(0, text_y, ">"); - } /* OK/Del/Cancel buttons */ button_h = MAX(MIN_GRID_SIZE*2, button_h); text_y = (button_h - text_h) / 2 + 1; @@ -1061,7 +1597,8 @@ static int keyboard_touchscreen(struct keyboard_parameters *pm, const int sc_w = sc->getwidth(), sc_h = sc->getheight(); int button_h = MAX(MIN_GRID_SIZE*2, sc->getcharheight()); #ifdef HAVE_MORSE_INPUT - if (state->morse_mode && y < pm->main_y - pm->keyboard_margin) + if (state->keyboard_mode == KBD_MODE_MORSE && + y < pm->main_y - pm->keyboard_margin) { /* don't return ACTION_NONE since it has effect in morse mode. */ return button == BUTTON_TOUCHSCREEN? ACTION_KBD_SELECT: @@ -1072,12 +1609,11 @@ static int keyboard_touchscreen(struct keyboard_parameters *pm, #endif if (x < 0 || y < 0) return ACTION_NONE; - if (y < pm->lines*pm->font_h) + if (y < pm->window_height*pm->font_h) { - if (x/pm->font_w < pm->max_chars) + if (x/pm->font_w < pm->window_width) { /* picker area */ - state->changed = CHANGED_PICKER; pm->x = x/pm->font_w; pm->y = y/pm->font_h; pm->line_edit = false; @@ -1085,12 +1621,6 @@ static int keyboard_touchscreen(struct keyboard_parameters *pm, return ACTION_KBD_SELECT; } } - else if (y < pm->main_y - pm->keyboard_margin) - { - /* button to flip page */ - if (button == BUTTON_REL) - return ACTION_KBD_PAGE_FLIP; - } else if (y < sc_h - button_h) { /* edit line */ @@ -1119,164 +1649,248 @@ static int keyboard_touchscreen(struct keyboard_parameters *pm, } #endif -/* inserts the selected char */ -static void kbd_insert_selected(struct keyboard_parameters *pm, - struct edit_state *state) + +#ifdef PRED_TEXT +/* This is a very simple dictionary based text predictor. + The dictionary file is one word per line (\n terminated.) + at /.rockbox/pred_dict.txt. + + The first word in the file that matches the letters input + will be offered for completion. The dictionary should be + ordered with most common words first for better matching. + Dictionary words can be phrases containing spaces but the + code will only match the first phrase with the same first + word. + + Needs to reboot to reload dictionary. + +*/ +#include "ctype.h" +#include "string.h" + +static bool dict_loaded = false, dict_changed = false; +static char dictionary[MAX_DICT]; + +static void kbd_learn_text(char *input) { - /* find input char */ - unsigned short ch = get_kbd_ch(pm, pm->x, pm->y); + /* dictionary end, word start, word end */ + int de,ws,we,i,len; + char *line, word[MAX_DICT_WORD+1]; - /* check for hangul input */ - if (ch >= 0x3131 && ch <= 0x3163) - { - unsigned short tmp; + if ( ! dict_loaded ) + return; - if (!state->hangul) - { - state->hlead = state->hvowel = state->htail = 0; - state->hangul = true; - } + for ( de = 0; dictionary[de]; de++ ) + if ( de == MAX_DICT ) + return; - if (!state->hvowel) + line = input; + + while(1) + { + /* find word start */ + for ( ws = 0; line[ws] == ' '; ws++ ); + if ( line[ws] == 0 ) + return; + /* find word end */ + for ( we = ws; line[we] != ' ' && line[we] != 0 ; we++ ); + len = we-ws; + if ( de+len >= MAX_DICT ) { + splash(HZ,"No room.");return;} + + if ( len >= MAX_DICT_WORD ) { + splash(HZ,"Word too big.");return;} + + /* don't save small words */ + if ( len < 3 ) { - state->hvowel = ch; + line += we; + continue; } - else if (!state->htail) + + /* check if it's in there already */ + /* FIXME: do something smart about case ?*/ + for ( i=0; i < len; i++ ) + word[i] = line[i+ws]; + word[len]=0; + if ( strcasestr( dictionary, word ) != NULL ) { - state->htail = ch; + line += we; + continue; } - else - { - /* previous hangul complete */ - /* check whether tail is actually lead of next char */ - tmp = hangul_join(state->htail, ch, 0); - if (tmp != 0xfffd) - { - tmp = hangul_join(state->hlead, state->hvowel, 0); - kbd_delchar(state); - kbd_inschar(state, tmp); - /* insert dummy char */ - kbd_inschar(state, ' '); - state->hlead = state->htail; - state->hvowel = ch; - state->htail = 0; - } - else - { - state->hvowel = state->htail = 0; - state->hlead = ch; - } - } + splashf(HZ/3,"Adding %s",word); + dict_changed = true; - /* combine into hangul */ - tmp = hangul_join(state->hlead, state->hvowel, state->htail); + /* shift dictionary forward */ + memmove( dictionary+len+1, dictionary, de ); - if (tmp != 0xfffd) + /* copy word */ + strcpy( dictionary, word ); + dictionary[len]='\n'; + de += len; + line += we; + } +} + +static void kbd_save_predicted() +{ + int length; + + if ( dict_loaded && dict_changed ) + { + int fd = open("/.rockbox/pred_dict.txt", O_WRONLY|O_BINARY); + if (fd < 0) { - kbd_delchar(state); - ch = tmp; + splash(HZ,"Can't open file"); + return; } - else + for ( length = 0; dictionary[length]; length++ ) + if ( length == MAX_DICT ) + break; + + if ( write( fd, dictionary, length ) != length ) { - state->hvowel = state->htail = 0; - state->hlead = ch; + splash(HZ,"Write error"); } + close(fd); } - else - { - state->hangul = false; - } - - /* insert char */ - kbd_inschar(state, ch); + return; } -static void kbd_backspace(struct edit_state *state) -{ - unsigned short ch; - if (state->hangul) - { - if (state->htail) - state->htail = 0; - else if (state->hvowel) - state->hvowel = 0; - else - state->hangul = false; - } - kbd_delchar(state); +static void kbd_load_predicted() +{ + int length; - if (state->hangul) + if ( ! dict_loaded ) { - if (state->hvowel) - ch = hangul_join(state->hlead, state->hvowel, state->htail); - else - ch = state->hlead; - kbd_inschar(state, ch); + int fd = open("/.rockbox/pred_dict.txt", O_RDONLY|O_BINARY); + if (fd < 0) + return; /* File Open Error */ + length = read(fd, dictionary, MAX_DICT); + if (length < 0) + return; /* Read Error */ + else { + dictionary[length] = 0; + dict_loaded = true; + } + close(fd); } } -static void kbd_move_cursor(struct edit_state *state, int dir) +static void kbd_draw_predicted(struct keyboard_parameters *pm, + struct screen *sc, struct edit_state *state) { - state->hangul = false; - state->editpos += dir; + int i, left = -1, length; + static int last_editpos = -1; + char *partial, *dict; + + if ( !dict_loaded ) + return; - if (state->editpos >= 0 && state->editpos <= state->len_utf8) + /* be lazy if edit cursor hasn't moved */ + if ( state->editpos == last_editpos ) { - state->changed = CHANGED_CURSOR; + sc->putsxy(0, pm->main_y+pm->font_h, state->pred_word); + return; } else - { - state->editpos -= dir; -#if CONFIG_CODEC == SWCODEC - if (global_settings.talk_menu) - beep_play(1000, 150, 1500); -#endif - } -} + last_editpos = state->editpos; -static void kbd_move_picker_horizontal(struct keyboard_parameters *pm, - struct edit_state *state, int dir) -{ - state->changed = CHANGED_PICKER; + /* Start with nothing predicted */ + state->pred_word[0] = 0; - pm->x += dir; - if (pm->x < 0) - { - if (--pm->page < 0) - pm->page = pm->pages - 1; - pm->x = pm->max_chars - 1; - } - else if (pm->x >= pm->max_chars) + dict = dictionary; /* Points to current dictionary word */ + i = state->editpos; + + if ( state->editpos != state->len_utf8 ) + return; + + while( --i >= 0 ) /* find left of word */ + if ( state->text[utf8seek(state->text,i)] != ' ' ) + left = i; + else + break; + + if ( left == -1 ) /* whitespace */ + return; + + /* search for matching word */ + length = utf8seek(state->text,state->editpos) - + utf8seek(state->text,left); + + partial = &state->text[utf8seek(state->text,left)]; + for ( i = 0; i <= length ; ) { - if (++pm->page >= pm->pages) - pm->page = 0; - pm->x = 0; + if ( dict[i] == '\n' ) + { + /* already typed out this whole word, look for another */ + dict += i +1; + i = 0; + continue; + } + if ( dict[i] == 0 ) + { + /* end of dictionary, give up */ + return; + } + if ( partial[i] == dict[i] ) + { + i++; + continue; + } + /* Case fuzz on first letter */ + if ( !i && tolower(partial[i]) == tolower(dict[i]) ) + { + i++; + continue; + } + if ( i == length ) /* got a match */ + { + break; + } + /* mismatch, reset to next word */ + while ( dict[++i] != '\n' ) + if ( dict[i] == 0 ) + return; + dict += i + 1; + i = 0; } + + /* get length of dictionary word in bytes */ + for ( i = 0 ; dict[i] != '\n' && dict[i] != 0 ; + i += utf8seek( dict,1) ) + if ( i >= MAX_DICT_WORD ) + { + i = MAX_DICT_WORD; + break; + } + /* copy */ + state->pred_word[i] = 0; + while ( --i >= 0 ) + state->pred_word[i] = dict[i]; + state->pred_input_len = length; + sc->putsxy(0, pm->main_y+pm->font_h, state->pred_word); } -static void kbd_move_picker_vertical(struct keyboard_parameters *pm, - struct edit_state *state, int dir) +static void kbd_insert_predicted(struct edit_state *state) { - state->changed = CHANGED_PICKER; + int i; -#ifdef HAVE_MORSE_INPUT - if (state->morse_mode) - { - pm->line_edit = !pm->line_edit; + i = utf8seek(state->text,state->editpos); + if ( i + (int)strlen(state->pred_word) - + state->pred_input_len >= state->buflen ) return; - } -#endif /* HAVE_MORSE_INPUT */ - pm->y += dir; - if (pm->line_edit) - { - pm->y = (dir > 0 ? 0 : pm->lines - 1); - pm->line_edit = false; - } - else if (pm->y < 0 || pm->y >= pm->lines) + if( state->pred_word[0] ) { - pm->line_edit = true; + strcpy( i + state->text, + state->pred_word + state->pred_input_len ); + + while ( state->text[utf8seek(state->text,state->editpos )] != 0 ) + state->editpos++; + return; } } +#endif diff --git a/apps/settings.h b/apps/settings.h index 62ae038..8d63730 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -773,9 +773,11 @@ struct user_settings bool sleeptimer_on_startup; bool keypress_restarts_sleeptimer; -#ifdef HAVE_MORSE_INPUT - bool morse_input; /* text input method setting */ +#if defined(HAVE_MORSE_INPUT) || defined(HAVE_SCROLLWHEEL) + int keyboard_mode; #endif + unsigned char kbd_picker_font[MAX_FILENAME+1]; + unsigned char kbd_edit_font[MAX_FILENAME+1]; #ifdef HAVE_HOTKEY /* hotkey assignments - acceptable values are in diff --git a/apps/settings_list.c b/apps/settings_list.c index 9b1ec44..c199a1f 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -2089,8 +2089,25 @@ const struct settings_list settings[] = { #endif #endif -#ifdef HAVE_MORSE_INPUT - OFFON_SETTING(0, morse_input, LANG_MORSE_INPUT, false, "morse input", NULL), +#if defined (HAVE_SCROLLWHEEL) && defined (HAVE_MORSE_INPUT) + CHOICE_SETTING(0, keyboard_mode, LANG_KBD_MODE, 0, "keyboard mode", + "Standard,Sideways,Keep_Rollin,Scroll_1D,Row_Column,Morse", NULL, 6, + ID2P(LANG_KBD_MODE_STANDARD), ID2P(LANG_KBD_MODE_SIDEWAYS), + ID2P(LANG_KBD_MODE_KEEP_ROLLIN), ID2P(LANG_KBD_MODE_SCROLL_1D), + ID2P(LANG_KBD_MODE_ROW_COL), ID2P(LANG_KBD_MODE_MORSE) ), +#else +#ifdef HAVE_MORSE_INPUT /* No scrollwheel */ + CHOICE_SETTING(0, keyboard_mode, LANG_KBD_MODE, 0, "keyboard mode", + "Standard,Morse", NULL, 2, + ID2P(LANG_KBD_MODE_STANDARD), ID2P(LANG_KBD_MODE_MORSE)), +#endif +#ifdef HAVE_SCROLLWHEEL /* No Morse */ + CHOICE_SETTING(0, keyboard_mode, LANG_KBD_MODE, 0, "keyboard mode", + "Standard,Sideways,Keep_Rollin,Scroll_1D,Row_Column", NULL, 5, + ID2P(LANG_KBD_MODE_STANDARD), ID2P(LANG_KBD_MODE_SIDEWAYS), + ID2P(LANG_KBD_MODE_KEEP_ROLLIN), ID2P(LANG_KBD_MODE_SCROLL_1D), + ID2P(LANG_KBD_MODE_ROW_COL)), +#endif #endif #ifdef HAVE_HOTKEY