blob: ceb8de00fbba52aa8de79812933db05807b6515b [file] [log] [blame]
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Nicolas Pennequin396aeaf2009-03-23 17:08:46 +000010 * Copyright (C) 2002 by Björn Stenberg
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +000011 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * 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.
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +000021#include "kernel.h"
Jens Arnold0b31a002005-02-07 00:56:26 +000022#include "system.h"
Thomas Martitz50a6ca32010-05-06 21:04:40 +000023#include "string-extra.h"
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +000024#include "font.h"
Björn Stenbergaa2972d2003-03-10 15:09:27 +000025#include "screens.h"
Jörg Hohensohn9e049572004-05-21 06:29:55 +000026#include "talk.h"
27#include "settings.h"
Linus Nielsen Feltzingade5d7b2004-07-26 16:06:59 +000028#include "misc.h"
Marcoen Hirschbergb0fee172005-12-06 13:27:15 +000029#include "rbunicode.h"
Kevin Ferrare1a1abf22005-11-20 01:02:14 +000030#include "buttonbar.h"
Miika Pekkarinen9d918c92005-12-02 19:41:09 +000031#include "logf.h"
Frank Dischner75c3d0b2006-03-29 16:21:42 +000032#include "hangul.h"
Martin Scarratt0ba22042006-08-22 13:21:13 +000033#include "action.h"
Jonathan Gordon6a5cc0b2007-04-16 09:14:36 +000034#include "icon.h"
Stéphane Doyond529a382007-10-10 02:28:58 +000035#include "pcmbuf.h"
36#include "lang.h"
Bertrik Sikkene15f8a22008-05-03 08:35:14 +000037#include "keyboard.h"
Jonathan Gordon45aa9a22009-01-05 10:25:41 +000038#include "viewport.h"
Bertrik Sikken4a70a072009-03-08 20:57:37 +000039#include "file.h"
Thomas Martitz50d09bd2009-08-12 14:51:16 +000040#include "splash.h"
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +000041
Frank Dischner75c3d0b2006-03-29 16:21:42 +000042#ifndef O_BINARY
43#define O_BINARY 0
Jens Arnold13fcd682005-10-08 07:12:28 +000044#endif
45
Frank Dischner75c3d0b2006-03-29 16:21:42 +000046
Frank Dischner75c3d0b2006-03-29 16:21:42 +000047#define DEFAULT_MARGIN 6
48#define KBD_BUF_SIZE 500
Jörg Hohensohn705ad512004-10-22 17:00:30 +000049
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +000050#ifdef HAVE_TOUCHSCREEN
51#define MIN_GRID_SIZE 16
52#define GRID_SIZE(s, x) \
53 ((s) == SCREEN_MAIN && MIN_GRID_SIZE > (x) ? MIN_GRID_SIZE: (x))
54#endif
55
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +000056#if (CONFIG_KEYPAD == IRIVER_H100_PAD) \
57 || (CONFIG_KEYPAD == IRIVER_H300_PAD) \
58 || (CONFIG_KEYPAD == IPOD_1G2G_PAD) \
59 || (CONFIG_KEYPAD == IPOD_3G_PAD) \
60 || (CONFIG_KEYPAD == IPOD_4G_PAD) \
61 || (CONFIG_KEYPAD == IRIVER_H10_PAD) \
62 || (CONFIG_KEYPAD == GIGABEAT_PAD) \
63 || (CONFIG_KEYPAD == GIGABEAT_S_PAD) \
64 || (CONFIG_KEYPAD == MROBE100_PAD) \
65 || (CONFIG_KEYPAD == SANSA_E200_PAD) \
66 || (CONFIG_KEYPAD == PHILIPS_HDD1630_PAD) \
Szymon Dziok057806f2010-10-18 19:30:54 +000067 || (CONFIG_KEYPAD == PHILIPS_HDD6330_PAD) \
Szymon Dziokf8287b02010-02-11 20:04:09 +000068 || (CONFIG_KEYPAD == PHILIPS_SA9200_PAD) \
Tomasz Mońc40f5202011-11-29 11:18:59 +000069 || (CONFIG_KEYPAD == PBELL_VIBE500_PAD) \
Szymon Dziokaa8ba602014-10-08 16:29:40 +020070 || (CONFIG_KEYPAD == SANSA_CONNECT_PAD) \
Szymon Dziok877bd982014-10-08 16:47:16 +020071 || (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) \
Sebastian Leonhardte6cd53a2016-01-23 15:54:08 +010072 || (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
Szymon Dziokaa8ba602014-10-08 16:29:40 +020073
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +000074/* certain key combos toggle input mode between keyboard input and Morse input */
75#define KBD_TOGGLE_INPUT
Jörg Hohensohn705ad512004-10-22 17:00:30 +000076#endif
77
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +000078#define CHANGED_PICKER 1
79#define CHANGED_CURSOR 2
80#define CHANGED_TEXT 3
81
Michael Sevakis82b26d22007-03-06 07:59:25 +000082struct keyboard_parameters
83{
Martin Scarrattef8317b2006-07-19 12:07:51 +000084 unsigned short kbd_buf[KBD_BUF_SIZE];
Teruaki Kawashima4c658f72010-02-13 13:10:32 +000085 unsigned short max_line_len;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +000086 int default_lines;
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +000087 int last_k;
88 int last_i;
Martin Scarrattef8317b2006-07-19 12:07:51 +000089 int font_w;
90 int font_h;
Teruaki Kawashimaccf20782009-10-03 13:53:49 +000091 int text_w;
Martin Scarrattef8317b2006-07-19 12:07:51 +000092 int curfont;
Martin Scarrattef8317b2006-07-19 12:07:51 +000093 int main_y;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +000094#ifdef HAVE_MORSE_INPUT
Teruaki Kawashima7243fdc2009-11-09 14:26:20 +000095 int old_main_y;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +000096#endif
Martin Scarrattef8317b2006-07-19 12:07:51 +000097 int max_chars;
98 int max_chars_text;
99 int lines;
100 int pages;
101 int keyboard_margin;
Martin Scarrattef8317b2006-07-19 12:07:51 +0000102 int curpos;
103 int leftpos;
104 int page;
105 int x;
106 int y;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000107 bool line_edit;
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000108#ifdef HAVE_TOUCHSCREEN
109 bool show_buttons;
110#endif
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000111};
112
113struct edit_state
114{
115 char* text;
116 int buflen;
117 int len_utf8;
118 int editpos; /* Edit position on all screens */
119 bool cur_blink; /* Cursor on/off flag */
Michael Sevakis11e45a32007-03-06 05:43:04 +0000120 bool hangul;
121 unsigned short hlead, hvowel, htail;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000122#ifdef HAVE_MORSE_INPUT
123 bool morse_mode;
124 bool morse_reading;
125 unsigned char morse_code;
126 int morse_tick;
127#endif
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000128 int changed;
Martin Scarrattef8317b2006-07-19 12:07:51 +0000129};
Jörg Hohensohn705ad512004-10-22 17:00:30 +0000130
Michael Sevakis82b26d22007-03-06 07:59:25 +0000131static struct keyboard_parameters kbd_param[NB_SCREENS];
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000132static bool kbd_loaded = false;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000133
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000134#ifdef HAVE_MORSE_INPUT
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000135/* FIXME: We should put this to a configuration file. */
Boris Gjenero17ed3252011-12-17 18:31:55 +0000136static const char * const morse_alphabets =
Miika Pekkarinen783428d2005-12-21 12:46:50 +0000137 "abcdefghijklmnopqrstuvwxyz1234567890,.?-@ ";
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000138static const unsigned char morse_codes[] = {
139 0x05,0x18,0x1a,0x0c,0x02,0x12,0x0e,0x10,0x04,0x17,0x0d,0x14,0x07,
140 0x06,0x0f,0x16,0x1d,0x0a,0x08,0x03,0x09,0x11,0x0b,0x19,0x1b,0x1c,
Miika Pekkarinen783428d2005-12-21 12:46:50 +0000141 0x2f,0x27,0x23,0x21,0x20,0x30,0x38,0x3c,0x3e,0x3f,
Miika Pekkarinenda932dc2005-12-04 08:45:24 +0000142 0x73,0x55,0x4c,0x61,0x5a,0x80 };
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000143#endif
144
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000145/* Loads a custom keyboard into memory
146 call with NULL to reset keyboard */
147int load_kbd(unsigned char* filename)
148{
Björn Stenberg0942e2a2011-10-15 19:35:02 +0000149 int fd;
Teruaki Kawashimaed21ab12010-02-14 05:00:41 +0000150 int i, line_len, max_line_len;
Antoine Cellerier4735e8e2006-07-23 18:54:00 +0000151 unsigned char buf[4];
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000152 unsigned short *pbuf;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000153
Michael Sevakis11e45a32007-03-06 05:43:04 +0000154 if (filename == NULL)
155 {
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000156 kbd_loaded = false;
157 return 0;
158 }
159
Dominik Riebeling02103a22008-08-02 20:39:03 +0000160 fd = open_utf8(filename, O_RDONLY|O_BINARY);
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000161 if (fd < 0)
162 return 1;
163
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000164 pbuf = kbd_param[0].kbd_buf;
Teruaki Kawashima4c658f72010-02-13 13:10:32 +0000165 line_len = 0;
Teruaki Kawashimaed21ab12010-02-14 05:00:41 +0000166 max_line_len = 1;
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000167 i = 1;
168 while (read(fd, buf, 1) == 1 && i < KBD_BUF_SIZE-1)
Michael Sevakis11e45a32007-03-06 05:43:04 +0000169 {
170 /* check how many bytes to read for this character */
171 static const unsigned char sizes[4] = { 0x80, 0xe0, 0xf0, 0xf5 };
172 size_t count;
Teruaki Kawashimaccf20782009-10-03 13:53:49 +0000173 unsigned short ch;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000174
175 for (count = 0; count < ARRAYLEN(sizes); count++)
176 {
177 if (buf[0] < sizes[count])
178 break;
Martin Scarrattef8317b2006-07-19 12:07:51 +0000179 }
Martin Scarrattaf5393c2006-07-23 18:33:43 +0000180
Michael Sevakis11e45a32007-03-06 05:43:04 +0000181 if (count >= ARRAYLEN(sizes))
182 continue; /* Invalid size. */
183
184 if (read(fd, &buf[1], count) != (ssize_t)count)
185 {
Martin Scarrattaf5393c2006-07-23 18:33:43 +0000186 close(fd);
187 kbd_loaded = false;
188 return 1;
189 }
Antoine Cellerier4735e8e2006-07-23 18:54:00 +0000190
Teruaki Kawashimaccf20782009-10-03 13:53:49 +0000191 utf8decode(buf, &ch);
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000192 if (ch != 0xFEFF && ch != '\r') /* skip BOM & carriage returns */
193 {
Martin Scarrattaf5393c2006-07-23 18:33:43 +0000194 i++;
Teruaki Kawashima4c658f72010-02-13 13:10:32 +0000195 if (ch == '\n')
196 {
197 if (max_line_len < line_len)
198 max_line_len = line_len;
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000199 *pbuf = line_len;
200 pbuf += line_len + 1;
Teruaki Kawashima4c658f72010-02-13 13:10:32 +0000201 line_len = 0;
202 }
203 else
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000204 pbuf[++line_len] = ch;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000205 }
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000206 }
207
208 close(fd);
209 kbd_loaded = true;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000210
Teruaki Kawashimaed21ab12010-02-14 05:00:41 +0000211 if (max_line_len < line_len)
212 max_line_len = line_len;
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000213 if (i == 1 || line_len != 0) /* ignore last empty line */
214 {
215 *pbuf = line_len;
216 pbuf += line_len + 1;
217 }
218 *pbuf = 0xFEFF; /* mark end of characters */
219 i++;
Martin Scarrattef8317b2006-07-19 12:07:51 +0000220 FOR_NB_SCREENS(l)
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000221 {
222 struct keyboard_parameters *pm = &kbd_param[l];
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000223#if NB_SCREENS > 1
224 if (l > 0)
225 memcpy(pm->kbd_buf, kbd_param[0].kbd_buf, i*sizeof(unsigned short));
226#endif
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000227 /* initialize parameters */
228 pm->x = pm->y = pm->page = 0;
229 pm->default_lines = 0;
Teruaki Kawashima4c658f72010-02-13 13:10:32 +0000230 pm->max_line_len = max_line_len;
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000231 }
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000232
Michael Sevakis11e45a32007-03-06 05:43:04 +0000233 return 0;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000234}
235
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000236/* helper function to spell a char */
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000237static void kbd_spellchar(unsigned short c)
Jörg Hohensohn9e049572004-05-21 06:29:55 +0000238{
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000239 unsigned char tmp[5];
240 /* store char to pass to talk_spell */
241 unsigned char* utf8 = utf8encode(c, tmp);
242 *utf8 = 0;
Stéphane Doyond529a382007-10-10 02:28:58 +0000243
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000244 if (c == ' ')
245 talk_id(VOICE_BLANK, false);
246 else
247 talk_spell(tmp, false);
Jörg Hohensohn9e049572004-05-21 06:29:55 +0000248}
249
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000250static void kbd_inschar(struct edit_state *state, unsigned short ch)
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000251{
Teruaki Kawashima7243fdc2009-11-09 14:26:20 +0000252 int i, j, len;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000253 unsigned char tmp[4];
254 unsigned char* utf8;
255
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000256 len = strlen(state->text);
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000257 utf8 = utf8encode(ch, tmp);
Amaury Poulyd7871912017-01-16 00:10:38 +0100258 j = (intptr_t)utf8 - (intptr_t)tmp;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000259
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000260 if (len + j < state->buflen)
Michael Sevakis11e45a32007-03-06 05:43:04 +0000261 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000262 i = utf8seek(state->text, state->editpos);
263 utf8 = state->text + i;
Teruaki Kawashima7243fdc2009-11-09 14:26:20 +0000264 memmove(utf8 + j, utf8, len - i + 1);
265 memcpy(utf8, tmp, j);
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000266 state->editpos++;
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000267 state->changed = CHANGED_TEXT;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000268 }
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000269}
270
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000271static void kbd_delchar(struct edit_state *state)
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000272{
Teruaki Kawashima7243fdc2009-11-09 14:26:20 +0000273 int i, j, len;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000274 unsigned char* utf8;
275
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000276 if (state->editpos > 0)
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000277 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000278 state->editpos--;
279 len = strlen(state->text);
280 i = utf8seek(state->text, state->editpos);
281 utf8 = state->text + i;
Teruaki Kawashima7243fdc2009-11-09 14:26:20 +0000282 j = utf8seek(utf8, 1);
283 memmove(utf8, utf8 + j, len - i - j + 1);
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000284 state->changed = CHANGED_TEXT;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000285 }
Michael Sevakis11e45a32007-03-06 05:43:04 +0000286}
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000287
Michael Sevakis11e45a32007-03-06 05:43:04 +0000288/* Lookup k value based on state of param (pm) */
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000289static unsigned short get_kbd_ch(struct keyboard_parameters *pm, int x, int y)
Michael Sevakis11e45a32007-03-06 05:43:04 +0000290{
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000291 int i = 0, k = pm->page*pm->lines + y, n;
292 unsigned short *pbuf;
293 if (k >= pm->last_k)
294 {
295 i = pm->last_i;
296 k -= pm->last_k;
297 }
298 for (pbuf = &pm->kbd_buf[i]; (i = *pbuf) != 0xFEFF; pbuf += i + 1)
299 {
300 n = i ? (i + pm->max_chars - 1) / pm->max_chars : 1;
301 if (k < n) break;
302 k -= n;
303 }
304 if (y == 0 && i != 0xFEFF)
305 {
306 pm->last_k = pm->page*pm->lines - k;
307 pm->last_i = pbuf - pm->kbd_buf;
308 }
309 k = k * pm->max_chars + x;
310 return (*pbuf != 0xFEFF && k < *pbuf)? pbuf[k+1]: ' ';
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000311}
312
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000313static void kbd_calc_params(struct keyboard_parameters *pm,
314 struct screen *sc, struct edit_state *state);
315static void kbd_draw_picker(struct keyboard_parameters *pm,
316 struct screen *sc, struct edit_state *state);
317static void kbd_draw_edit_line(struct keyboard_parameters *pm,
318 struct screen *sc, struct edit_state *state);
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000319#ifdef HAVE_TOUCHSCREEN
320static void kbd_draw_buttons(struct keyboard_parameters *pm, struct screen *sc);
321static int keyboard_touchscreen(struct keyboard_parameters *pm,
322 struct screen *sc, struct edit_state *state);
323#endif
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000324static void kbd_insert_selected(struct keyboard_parameters *pm,
325 struct edit_state *state);
326static void kbd_backspace(struct edit_state *state);
327static void kbd_move_cursor(struct edit_state *state, int dir);
Teruaki Kawashima89033392010-06-09 12:08:25 +0000328static void kbd_move_picker_horizontal(struct keyboard_parameters *pm,
329 struct edit_state *state, int dir);
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000330static void kbd_move_picker_vertical(struct keyboard_parameters *pm,
331 struct edit_state *state, int dir);
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000332
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000333int kbd_input(char* text, int buflen)
334{
Miika Pekkarinen5da90fa2005-12-04 07:37:24 +0000335 bool done = false;
Michael Sevakis38be0e62007-03-06 08:19:00 +0000336 struct keyboard_parameters * const param = kbd_param;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000337 struct edit_state state;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000338 unsigned short ch;
Thomas Martitz50d09bd2009-08-12 14:51:16 +0000339 int ret = 0; /* assume success */
Martin Scarrattef8317b2006-07-19 12:07:51 +0000340 FOR_NB_SCREENS(l)
341 {
Jonathan Gordonb2eb44c2009-12-09 07:25:46 +0000342 viewportmanager_theme_enable(l, false, NULL);
Martin Scarrattef8317b2006-07-19 12:07:51 +0000343 }
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000344
Peter D'Hoyef76122f2008-05-29 20:32:39 +0000345#ifdef HAVE_BUTTONBAR
Kevin Ferrare1a1abf22005-11-20 01:02:14 +0000346 struct gui_buttonbar buttonbar;
Linus Nielsen Feltzingdd939aa2006-03-11 22:31:53 +0000347 bool buttonbar_config = global_settings.buttonbar;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000348
Linus Nielsen Feltzingdd939aa2006-03-11 22:31:53 +0000349 global_settings.buttonbar = true;
Kevin Ferrare1a1abf22005-11-20 01:02:14 +0000350 gui_buttonbar_init(&buttonbar);
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000351 gui_buttonbar_set_display(&buttonbar, &screens[SCREEN_MAIN]);
Kevin Ferrare1a1abf22005-11-20 01:02:14 +0000352#endif
Michael Sevakis11e45a32007-03-06 05:43:04 +0000353
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000354 /* initialize state */
355 state.text = text;
356 state.buflen = buflen;
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000357 /* Initial edit position is after last character */
358 state.editpos = utf8length(state.text);
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000359 state.cur_blink = true;
360#ifdef HAVE_MORSE_INPUT
361 state.morse_mode = global_settings.morse_input;
362 state.morse_reading = false;
363#endif
364 state.hangul = false;
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000365 state.changed = 0;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000366
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000367 if (!kbd_loaded)
368 {
369 /* Copy default keyboard to buffer */
370 FOR_NB_SCREENS(l)
Antoine Cellerier8eba20a2006-07-23 17:16:38 +0000371 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000372 struct keyboard_parameters *pm = &param[l];
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000373 unsigned short *pbuf;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000374 const unsigned char *p;
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000375 int len = 0;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000376
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000377#if LCD_WIDTH >= 160 && LCD_HEIGHT >= 96
378 struct screen *sc = &screens[l];
379
380 if (sc->getwidth() >= 160 && sc->getheight() >= 96)
381 {
382 p = "ABCDEFG abcdefg !?\" @#$%+'\n"
383 "HIJKLMN hijklmn 789 &_()-`\n"
384 "OPQRSTU opqrstu 456 §|{}/<\n"
385 "VWXYZ., vwxyz.,0123 ~=[]*>\n"
386 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË ¢£¤¥¦§©®\n"
387 "àáâãäåæ ìíîï èéêë «»°ºª¹²³\n"
388 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ ¯±×÷¡¿µ·\n"
389 "òóôõöø çðþýÿ ùúûü ¼½¾¬¶¨:;";
390
391 pm->default_lines = 8;
Teruaki Kawashima4c658f72010-02-13 13:10:32 +0000392 pm->max_line_len = 26;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000393 }
394 else
395#endif /* LCD_WIDTH >= 160 && LCD_HEIGHT >= 96 */
396 {
397 p = "ABCDEFG !?\" @#$%+'\n"
398 "HIJKLMN 789 &_()-`\n"
399 "OPQRSTU 456 §|{}/<\n"
400 "VWXYZ.,0123 ~=[]*>\n"
401
402 "abcdefg ¢£¤¥¦§©®¬\n"
403 "hijklmn «»°ºª¹²³¶\n"
404 "opqrstu ¯±×÷¡¿µ·¨\n"
405 "vwxyz., :;¼½¾ \n"
406
407 "ÀÁÂÃÄÅÆ ÌÍÎÏ ÈÉÊË\n"
408 "àáâãäåæ ìíîï èéêë\n"
409 "ÓÒÔÕÖØ ÇÐÞÝß ÙÚÛÜ\n"
410 "òóôõöø çðþýÿ ùúûü";
411
412 pm->default_lines = 4;
Teruaki Kawashima4c658f72010-02-13 13:10:32 +0000413 pm->max_line_len = 18;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000414 }
415
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000416 pbuf = pm->kbd_buf;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000417 while (*p)
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000418 {
419 p = utf8decode(p, &pbuf[len+1]);
420 if (pbuf[len+1] == '\n')
421 {
422 *pbuf = len;
423 pbuf += len+1;
424 len = 0;
425 }
426 else
427 len++;
428 }
429 *pbuf = len;
430 pbuf[len+1] = 0xFEFF; /* mark end of characters */
Michael Sevakis11e45a32007-03-06 05:43:04 +0000431
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000432 /* initialize parameters */
433 pm->x = pm->y = pm->page = 0;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000434 }
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000435 kbd_loaded = true;
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000436 }
Michael Sevakis11e45a32007-03-06 05:43:04 +0000437
Martin Scarrattef8317b2006-07-19 12:07:51 +0000438 FOR_NB_SCREENS(l)
439 {
Michael Sevakis11e45a32007-03-06 05:43:04 +0000440 struct keyboard_parameters *pm = &param[l];
441 struct screen *sc = &screens[l];
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000442 kbd_calc_params(pm, sc, &state);
Antoine Cellerier8eba20a2006-07-23 17:16:38 +0000443 }
Michael Sevakis11e45a32007-03-06 05:43:04 +0000444
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000445 if (global_settings.talk_menu) /* voice UI? */
446 talk_spell(state.text, true); /* spell initial text */
Jörg Hohensohn9e049572004-05-21 06:29:55 +0000447
Michael Sevakis11e45a32007-03-06 05:43:04 +0000448 while (!done)
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000449 {
Michael Sevakis11e45a32007-03-06 05:43:04 +0000450 /* These declarations are assigned to the screen on which the key
451 action occurred - pointers save a lot of space over array notation
452 when accessing the same array element countless times */
453 int button;
454#if NB_SCREENS > 1
455 int button_screen;
456#else
457 const int button_screen = 0;
458#endif
459 struct keyboard_parameters *pm;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000460
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000461 state.len_utf8 = utf8length(state.text);
Michael Sevakis11e45a32007-03-06 05:43:04 +0000462
Martin Scarrattef8317b2006-07-19 12:07:51 +0000463 FOR_NB_SCREENS(l)
Jens Arnoldb5991b22006-04-22 13:06:57 +0000464 {
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000465 /* declare scoped pointers inside screen loops - hide the
466 declarations from previous block level */
Michael Sevakis11e45a32007-03-06 05:43:04 +0000467 struct keyboard_parameters *pm = &param[l];
468 struct screen *sc = &screens[l];
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000469 sc->clear_display();
470 kbd_draw_picker(pm, sc, &state);
471 kbd_draw_edit_line(pm, sc, &state);
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000472#ifdef HAVE_TOUCHSCREEN
473 if (pm->show_buttons)
474 kbd_draw_buttons(pm, sc);
475#endif
Martin Scarrattef8317b2006-07-19 12:07:51 +0000476 }
Michael Sevakis11e45a32007-03-06 05:43:04 +0000477
Peter D'Hoyef76122f2008-05-29 20:32:39 +0000478#ifdef HAVE_BUTTONBAR
Jens Arnoldb5991b22006-04-22 13:06:57 +0000479 /* draw the button bar */
480 gui_buttonbar_set(&buttonbar, "Shift", "OK", "Del");
481 gui_buttonbar_draw(&buttonbar);
482#endif
483
Michael Sevakis11e45a32007-03-06 05:43:04 +0000484 FOR_NB_SCREENS(l)
Michael Sevakis11e45a32007-03-06 05:43:04 +0000485 screens[l].update();
Jens Arnoldb5991b22006-04-22 13:06:57 +0000486
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000487 state.cur_blink = !state.cur_blink;
488
Teruaki Kawashimab7f728d2010-01-16 13:54:10 +0000489 button = get_action(
490#ifdef HAVE_MORSE_INPUT
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000491 state.morse_mode? CONTEXT_MORSE_INPUT:
Teruaki Kawashimab7f728d2010-01-16 13:54:10 +0000492#endif
493 CONTEXT_KEYBOARD, HZ/2);
Michael Sevakis00af7c72007-03-06 05:55:23 +0000494#if NB_SCREENS > 1
Michael Sevakis11e45a32007-03-06 05:43:04 +0000495 button_screen = (get_action_statuscode(NULL) & ACTION_REMOTE) ? 1 : 0;
496#endif
497 pm = &param[button_screen];
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000498#ifdef HAVE_TOUCHSCREEN
499 if (button == ACTION_TOUCHSCREEN)
Rafaël Carréc78d55a2010-09-19 08:17:02 +0000500 {
501 struct screen *sc = &screens[button_screen];
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000502 button = keyboard_touchscreen(pm, sc, &state);
Rafaël Carréc78d55a2010-09-19 08:17:02 +0000503 }
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000504#endif
Michael Sevakis11e45a32007-03-06 05:43:04 +0000505
Teruaki Kawashimab6cd0452009-11-06 12:53:02 +0000506 /* Remap some buttons to allow to move
507 * cursor in line edit mode and morse mode. */
Teruaki Kawashima89033392010-06-09 12:08:25 +0000508 if (pm->line_edit
509#ifdef HAVE_MORSE_INPUT
510 || state.morse_mode
511#endif /* HAVE_MORSE_INPUT */
512 )
Miika Pekkarinenda932dc2005-12-04 08:45:24 +0000513 {
Martin Scarratt0ba22042006-08-22 13:21:13 +0000514 if (button == ACTION_KBD_LEFT)
515 button = ACTION_KBD_CURSOR_LEFT;
516 if (button == ACTION_KBD_RIGHT)
517 button = ACTION_KBD_CURSOR_RIGHT;
Miika Pekkarinenda932dc2005-12-04 08:45:24 +0000518 }
Zakk Robertsa1db4312006-04-22 09:43:43 +0000519
Michael Sevakis11e45a32007-03-06 05:43:04 +0000520 switch ( button )
521 {
Teruaki Kawashima7243fdc2009-11-09 14:26:20 +0000522 case ACTION_KBD_DONE:
523 /* accepts what was entered and continues */
524 ret = 0;
525 done = true;
526 break;
527
Martin Scarratt0ba22042006-08-22 13:21:13 +0000528 case ACTION_KBD_ABORT:
Teruaki Kawashima61dc1c52009-10-04 14:45:29 +0000529 ret = -1;
530 done = true;
Björn Stenberg58dff172003-01-15 13:48:54 +0000531 break;
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000532
Martin Scarratt0ba22042006-08-22 13:21:13 +0000533 case ACTION_KBD_PAGE_FLIP:
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000534#ifdef HAVE_MORSE_INPUT
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000535 if (state.morse_mode)
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000536 break;
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000537#endif
Michael Sevakis11e45a32007-03-06 05:43:04 +0000538 if (++pm->page >= pm->pages)
Teruaki Kawashima61dc1c52009-10-04 14:45:29 +0000539 pm->page = 0;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000540
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000541 state.changed = CHANGED_PICKER;
Björn Stenberg58dff172003-01-15 13:48:54 +0000542 break;
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000543
Martin Scarratt0ba22042006-08-22 13:21:13 +0000544 case ACTION_KBD_RIGHT:
Teruaki Kawashima89033392010-06-09 12:08:25 +0000545 kbd_move_picker_horizontal(pm, &state, 1);
Björn Stenberg58dff172003-01-15 13:48:54 +0000546 break;
Martin Scarratt0ba22042006-08-22 13:21:13 +0000547
548 case ACTION_KBD_LEFT:
Teruaki Kawashima89033392010-06-09 12:08:25 +0000549 kbd_move_picker_horizontal(pm, &state, -1);
Björn Stenberg58dff172003-01-15 13:48:54 +0000550 break;
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000551
Martin Scarratt0ba22042006-08-22 13:21:13 +0000552 case ACTION_KBD_DOWN:
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000553 kbd_move_picker_vertical(pm, &state, 1);
Björn Stenberg58dff172003-01-15 13:48:54 +0000554 break;
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000555
Martin Scarratt0ba22042006-08-22 13:21:13 +0000556 case ACTION_KBD_UP:
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000557 kbd_move_picker_vertical(pm, &state, -1);
Björn Stenberg58dff172003-01-15 13:48:54 +0000558 break;
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000559
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000560#ifdef HAVE_MORSE_INPUT
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000561#ifdef KBD_TOGGLE_INPUT
562 case ACTION_KBD_MORSE_INPUT:
563 state.morse_mode = !state.morse_mode;
Teruaki Kawashima89033392010-06-09 12:08:25 +0000564 state.changed = CHANGED_PICKER;
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000565
566 FOR_NB_SCREENS(l)
567 {
568 struct keyboard_parameters *pm = &param[l];
569 int y = pm->main_y;
570 pm->main_y = pm->old_main_y;
571 pm->old_main_y = y;
572 }
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000573 break;
574#endif /* KBD_TOGGLE_INPUT */
575
Martin Scarratt0ba22042006-08-22 13:21:13 +0000576 case ACTION_KBD_MORSE_SELECT:
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000577 if (state.morse_mode && state.morse_reading)
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000578 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000579 state.morse_code <<= 1;
580 if ((current_tick - state.morse_tick) > HZ/5)
581 state.morse_code |= 0x01;
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000582 }
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000583 break;
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000584#endif /* HAVE_MORSE_INPUT */
Zakk Robertsa1db4312006-04-22 09:43:43 +0000585
Martin Scarratt0ba22042006-08-22 13:21:13 +0000586 case ACTION_KBD_SELECT:
Teruaki Kawashima89033392010-06-09 12:08:25 +0000587 /* select doubles as backspace in line_edit */
588 if (pm->line_edit)
589 kbd_backspace(&state);
590 else
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000591#ifdef HAVE_MORSE_INPUT
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000592 if (state.morse_mode)
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000593 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000594 state.morse_tick = current_tick;
Michael Sevakis11e45a32007-03-06 05:43:04 +0000595
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000596 if (!state.morse_reading)
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000597 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000598 state.morse_reading = true;
599 state.morse_code = 1;
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000600 }
Björn Stenberg58dff172003-01-15 13:48:54 +0000601 }
Jens Arnold7b95e602004-11-14 23:08:08 +0000602 else
Teruaki Kawashima40638bf2009-11-08 14:24:47 +0000603#endif /* HAVE_MORSE_INPUT */
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000604 kbd_insert_selected(pm, &state);
Jens Arnold7b95e602004-11-14 23:08:08 +0000605 break;
606
Martin Scarratt0ba22042006-08-22 13:21:13 +0000607 case ACTION_KBD_BACKSPACE:
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000608 kbd_backspace(&state);
Björn Stenberg58dff172003-01-15 13:48:54 +0000609 break;
Björn Stenbergaa2972d2003-03-10 15:09:27 +0000610
Martin Scarratt0ba22042006-08-22 13:21:13 +0000611 case ACTION_KBD_CURSOR_RIGHT:
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000612 kbd_move_cursor(&state, 1);
Björn Stenbergaa2972d2003-03-10 15:09:27 +0000613 break;
614
Martin Scarratt0ba22042006-08-22 13:21:13 +0000615 case ACTION_KBD_CURSOR_LEFT:
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000616 kbd_move_cursor(&state, -1);
Björn Stenbergaa2972d2003-03-10 15:09:27 +0000617 break;
618
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000619 case ACTION_NONE:
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000620#ifdef HAVE_MORSE_INPUT
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000621 if (state.morse_reading)
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000622 {
Michael Sevakis11e45a32007-03-06 05:43:04 +0000623 int j;
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000624 logf("Morse: 0x%02x", state.morse_code);
625 state.morse_reading = false;
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000626
627 for (j = 0; morse_alphabets[j] != '\0'; j++)
628 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000629 if (morse_codes[j] == state.morse_code)
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000630 break ;
631 }
632
633 if (morse_alphabets[j] == '\0')
634 {
635 logf("Morse code not found");
636 break ;
637 }
Frank Dischner75c3d0b2006-03-29 16:21:42 +0000638
Frank Dischner367b8ec2006-03-31 13:59:04 +0000639 /* turn off hangul input */
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000640 state.hangul = false;
641 kbd_inschar(&state, morse_alphabets[j]);
Miika Pekkarinen9d918c92005-12-02 19:41:09 +0000642 }
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000643#endif /* HAVE_MORSE_INPUT */
Linus Nielsen Feltzing6afd0a72003-11-04 12:36:55 +0000644 break;
Linus Nielsen Feltzingade5d7b2004-07-26 16:06:59 +0000645
646 default:
Michael Sevakis11e45a32007-03-06 05:43:04 +0000647 if (default_event_handler(button) == SYS_USB_CONNECTED)
648 {
Martin Scarrattef8317b2006-07-19 12:07:51 +0000649 FOR_NB_SCREENS(l)
650 screens[l].setfont(FONT_SYSFIXED);
Michael Sevakis11e45a32007-03-06 05:43:04 +0000651 }
Linus Nielsen Feltzingade5d7b2004-07-26 16:06:59 +0000652 break;
653
Michael Sevakis11e45a32007-03-06 05:43:04 +0000654 } /* end switch */
655
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000656 if (button != ACTION_NONE)
Jens Arnoldb5991b22006-04-22 13:06:57 +0000657 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000658 state.cur_blink = true;
Jens Arnoldb5991b22006-04-22 13:06:57 +0000659 }
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000660 if (global_settings.talk_menu) /* voice UI? */
661 {
662 if (state.changed == CHANGED_PICKER)
663 {
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000664 if (pm->line_edit)
665 {
666 talk_id(VOICE_EDIT, false);
667 }
668 else
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000669#ifdef HAVE_MORSE_INPUT
Teruaki Kawashima89033392010-06-09 12:08:25 +0000670 /* FIXME: We should talk something like Morse mode.. */
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000671 if (!state.morse_mode)
672#endif
673 {
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000674 ch = get_kbd_ch(pm, pm->x, pm->y);
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +0000675 kbd_spellchar(ch);
676 }
677 }
678 else if (state.changed == CHANGED_CURSOR)
679 {
680 int c = utf8seek(state.text, state.editpos);
681 kbd_spellchar(state.text[c]);
682 }
683 else if (state.changed == CHANGED_TEXT)
684 talk_spell(state.text, false); /* speak revised text */
685 }
686 state.changed = 0;
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000687 }
Michael Sevakis11e45a32007-03-06 05:43:04 +0000688
Peter D'Hoyef76122f2008-05-29 20:32:39 +0000689#ifdef HAVE_BUTTONBAR
Michael Sevakis11e45a32007-03-06 05:43:04 +0000690 global_settings.buttonbar = buttonbar_config;
Linus Nielsen Feltzingdd939aa2006-03-11 22:31:53 +0000691#endif
Michael Sevakis11e45a32007-03-06 05:43:04 +0000692
Thomas Martitz4c48b592009-08-16 22:20:11 +0000693 if (ret < 0)
694 splash(HZ/2, ID2P(LANG_CANCEL));
695
Teruaki Kawashima7243fdc2009-11-09 14:26:20 +0000696#if defined(HAVE_MORSE_INPUT) && defined(KBD_TOGGLE_INPUT)
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000697 if (global_settings.morse_input != state.morse_mode)
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000698 {
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000699 global_settings.morse_input = state.morse_mode;
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000700 settings_save();
701 }
Teruaki Kawashima7243fdc2009-11-09 14:26:20 +0000702#endif /* HAVE_MORSE_INPUT && KBD_TOGGLE_INPUT */
Teruaki Kawashima92fb1df2009-11-08 13:14:50 +0000703
Martin Scarrattef8317b2006-07-19 12:07:51 +0000704 FOR_NB_SCREENS(l)
Jonathan Gordonb2eb44c2009-12-09 07:25:46 +0000705 {
Martin Scarrattef8317b2006-07-19 12:07:51 +0000706 screens[l].setfont(FONT_UI);
Jonathan Gordon9d1832c2009-12-21 05:19:12 +0000707 viewportmanager_theme_undo(l, false);
Teruaki Kawashimae2359ac2010-01-31 13:38:47 +0000708 }
Thomas Martitz18e40e02009-08-12 14:38:25 +0000709 return ret;
Björn Stenbergc8cb6ff2002-12-04 15:04:43 +0000710}
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000711
712static void kbd_calc_params(struct keyboard_parameters *pm,
713 struct screen *sc, struct edit_state *state)
714{
715 struct font* font;
716 const unsigned char *p;
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000717 unsigned short ch, *pbuf;
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000718 int icon_w, sc_w, sc_h, w;
719 int i, total_lines;
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000720#ifdef HAVE_TOUCHSCREEN
721 int button_h = 0;
722 bool flippage_button = false;
723 pm->show_buttons = (sc->screen_type == SCREEN_MAIN &&
724 (touchscreen_get_mode() == TOUCHSCREEN_POINT));
725#endif
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000726
Jonathan Gordonf19f3ef2011-11-08 10:09:33 +0000727 pm->curfont = pm->default_lines ? FONT_SYSFIXED : sc->getuifont();
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000728 font = font_get(pm->curfont);
729 pm->font_h = font->height;
730
731 /* check if FONT_UI fits the screen */
732 if (2*pm->font_h + 3 + BUTTONBAR_HEIGHT > sc->getheight())
733 {
734 pm->curfont = FONT_SYSFIXED;
735 font = font_get(FONT_SYSFIXED);
736 pm->font_h = font->height;
737 }
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000738#ifdef HAVE_TOUCHSCREEN
739 pm->font_h = GRID_SIZE(sc->screen_type, pm->font_h);
740#endif
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000741
742 /* find max width of keyboard glyphs.
743 * since we're going to be adding spaces,
744 * max width is at least their width */
745 pm->font_w = font_get_width(font, ' ');
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000746 for (pbuf = pm->kbd_buf; *pbuf != 0xFEFF; pbuf += i)
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000747 {
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000748 for (i = 0; ++i <= *pbuf; )
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000749 {
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000750 w = font_get_width(font, pbuf[i]);
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000751 if (pm->font_w < w)
752 pm->font_w = w;
753 }
754 }
755
756 /* Find max width for text string */
757 pm->text_w = pm->font_w;
758 p = state->text;
759 while (*p)
760 {
761 p = utf8decode(p, &ch);
762 w = font_get_width(font, ch);
763 if (pm->text_w < w)
764 pm->text_w = w;
765 }
766
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000767#ifdef HAVE_TOUCHSCREEN
768 pm->font_w = GRID_SIZE(sc->screen_type, pm->font_w);
769#endif
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000770 /* calculate how many characters to put in a row. */
771 icon_w = get_icon_width(sc->screen_type);
772 sc_w = sc->getwidth();
Teruaki Kawashima4c658f72010-02-13 13:10:32 +0000773 if (pm->font_w < sc_w / pm->max_line_len)
774 pm->font_w = sc_w / pm->max_line_len;
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000775 pm->max_chars = sc_w / pm->font_w;
776 pm->max_chars_text = (sc_w - icon_w * 2 - 2) / pm->text_w;
777 if (pm->max_chars_text < 3 && icon_w > pm->text_w)
778 pm->max_chars_text = sc_w / pm->text_w - 2;
779
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000780 /* calculate pm->pages and pm->lines */
781 sc_h = sc->getheight();
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000782#ifdef HAVE_TOUCHSCREEN
783 /* add space for buttons */
784 if (pm->show_buttons)
785 {
786 /* reserve place for OK/Del/Cancel buttons, use ui font for them */
787 button_h = GRID_SIZE(sc->screen_type, sc->getcharheight());
788 sc_h -= MAX(MIN_GRID_SIZE*2, button_h);
789 }
790recalc_param:
791#endif
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000792 pm->lines = (sc_h - BUTTONBAR_HEIGHT) / pm->font_h - 1;
793
794 if (pm->default_lines && pm->lines > pm->default_lines)
795 pm->lines = pm->default_lines;
796
797 pm->keyboard_margin = sc_h - BUTTONBAR_HEIGHT
798 - (pm->lines+1)*pm->font_h;
799
800 if (pm->keyboard_margin < 3 && pm->lines > 1)
801 {
802 pm->lines--;
803 pm->keyboard_margin += pm->font_h;
804 }
805
806 if (pm->keyboard_margin > DEFAULT_MARGIN)
807 pm->keyboard_margin = DEFAULT_MARGIN;
808
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000809 total_lines = 0;
810 for (pbuf = pm->kbd_buf; (i = *pbuf) != 0xFEFF; pbuf += i + 1)
811 total_lines += (i ? (i + pm->max_chars - 1) / pm->max_chars : 1);
812
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000813 pm->pages = (total_lines + pm->lines - 1) / pm->lines;
814 pm->lines = (total_lines + pm->pages - 1) / pm->pages;
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000815#ifdef HAVE_TOUCHSCREEN
816 if (pm->pages > 1 && pm->show_buttons && !flippage_button)
817 {
818 /* add space for flip page button */
819 sc_h -= button_h;
820 flippage_button = true;
821 goto recalc_param;
822 }
823#endif
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000824 if (pm->page >= pm->pages)
825 pm->x = pm->y = pm->page = 0;
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000826
827 pm->main_y = pm->font_h*pm->lines + pm->keyboard_margin;
828 pm->keyboard_margin -= pm->keyboard_margin/2;
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +0000829#ifdef HAVE_TOUCHSCREEN
830 /* flip page button is put between piker and edit line */
831 if (flippage_button)
832 pm->main_y += button_h;
833#endif
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000834
835#ifdef HAVE_MORSE_INPUT
836 pm->old_main_y = sc_h - pm->font_h - BUTTONBAR_HEIGHT;
837 if (state->morse_mode)
838 {
839 int y = pm->main_y;
840 pm->main_y = pm->old_main_y;
841 pm->old_main_y = y;
842 }
843#endif
844}
845
846static void kbd_draw_picker(struct keyboard_parameters *pm,
847 struct screen *sc, struct edit_state *state)
848{
849 char outline[8];
850#ifdef HAVE_MORSE_INPUT
851 if (state->morse_mode)
852 {
853 const int w = 6, h = 8; /* sysfixed font width, height */
854 int i, j, x, y;
855 int sc_w = sc->getwidth(), sc_h = pm->main_y - pm->keyboard_margin - 1;
856
857 /* Draw morse code screen with sysfont */
858 sc->setfont(FONT_SYSFIXED);
859 x = 0;
860 y = 0;
861 outline[1] = '\0';
862
863 /* Draw morse code table with code descriptions. */
864 for (i = 0; morse_alphabets[i] != '\0'; i++)
865 {
866 int morse_code;
867
868 outline[0] = morse_alphabets[i];
869 sc->putsxy(x, y, outline);
870
871 morse_code = morse_codes[i];
872 for (j = 0; morse_code > 0x01; morse_code >>= 1)
873 j++;
874
875 x += w + 3 + j*4;
876 morse_code = morse_codes[i];
877 for (; morse_code > 0x01; morse_code >>= 1)
878 {
879 x -= 4;
880 if (morse_code & 0x01)
881 sc->fillrect(x, y + 2, 3, 4);
882 else
883 sc->fillrect(x, y + 3, 1, 2);
884 }
885
886 x += w*5 - 3;
887 if (x + w*6 >= sc_w)
888 {
889 x = 0;
890 y += h;
891 if (y + h >= sc_h)
892 break;
893 }
894 }
895 }
896 else
897#else
898 (void) state;
899#endif /* HAVE_MORSE_INPUT */
900 {
901 /* draw page */
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000902 int i, j;
903 int w, h;
904 unsigned short ch;
905 unsigned char *utf8;
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000906
907 sc->setfont(pm->curfont);
908
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000909 for (j = 0; j < pm->lines; j++)
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000910 {
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000911 for (i = 0; i < pm->max_chars; i++)
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000912 {
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +0000913 ch = get_kbd_ch(pm, i, j);
914 utf8 = utf8encode(ch, outline);
915 *utf8 = 0;
916
917 sc->getstringsize(outline, &w, &h);
918 sc->putsxy(i*pm->font_w + (pm->font_w-w) / 2,
919 j*pm->font_h + (pm->font_h-h) / 2, outline);
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000920 }
921 }
922
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000923 if (!pm->line_edit)
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +0000924 {
925 /* highlight the key that has focus */
926 sc->set_drawmode(DRMODE_COMPLEMENT);
927 sc->fillrect(pm->font_w*pm->x, pm->font_h*pm->y,
928 pm->font_w, pm->font_h);
929 sc->set_drawmode(DRMODE_SOLID);
930 }
931 }
932}
933
934static void kbd_draw_edit_line(struct keyboard_parameters *pm,
935 struct screen *sc, struct edit_state *state)
936{
937 char outline[8];
938 unsigned char *utf8;
939 int i = 0, j = 0, icon_w, w;
940 int sc_w = sc->getwidth();
941 int y = pm->main_y - pm->keyboard_margin;
942 int text_margin = (sc_w - pm->text_w * pm->max_chars_text) / 2;
943
944 /* Clear text area one pixel above separator line so any overdraw
945 doesn't collide */
946 screen_clear_area(sc, 0, y - 1, sc_w, pm->font_h + 6);
947
948 sc->hline(0, sc_w - 1, y);
949
950 /* write out the text */
951 sc->setfont(pm->curfont);
952
953 pm->leftpos = MAX(0, MIN(state->len_utf8, state->editpos + 2)
954 - pm->max_chars_text);
955 pm->curpos = state->editpos - pm->leftpos;
956 utf8 = state->text + utf8seek(state->text, pm->leftpos);
957
958 while (*utf8 && i < pm->max_chars_text)
959 {
960 j = utf8seek(utf8, 1);
961 strlcpy(outline, utf8, j+1);
962 sc->getstringsize(outline, &w, NULL);
963 sc->putsxy(text_margin + i*pm->text_w + (pm->text_w-w)/2,
964 pm->main_y, outline);
965 utf8 += j;
966 i++;
967 }
968
969 icon_w = get_icon_width(sc->screen_type);
970 if (pm->leftpos > 0)
971 {
972 /* Draw nicer bitmap arrow if room, else settle for "<". */
973 if (text_margin >= icon_w)
974 {
975 screen_put_icon_with_offset(sc, 0, 0,
976 (text_margin - icon_w) / 2,
977 pm->main_y, Icon_Reverse_Cursor);
978 }
979 else
980 {
981 sc->getstringsize("<", &w, NULL);
982 sc->putsxy(text_margin - w, pm->main_y, "<");
983 }
984 }
985
986 if (state->len_utf8 - pm->leftpos > pm->max_chars_text)
987 {
988 /* Draw nicer bitmap arrow if room, else settle for ">". */
989 if (text_margin >= icon_w)
990 {
991 screen_put_icon_with_offset(sc, 0, 0,
992 sc_w - (text_margin + icon_w) / 2,
993 pm->main_y, Icon_Cursor);
994 }
995 else
996 {
997 sc->putsxy(sc_w - text_margin, pm->main_y, ">");
998 }
999 }
1000
1001 /* cursor */
1002 i = text_margin + pm->curpos * pm->text_w;
1003
1004 if (state->cur_blink)
1005 sc->vline(i, pm->main_y, pm->main_y + pm->font_h - 1);
1006
1007 if (state->hangul) /* draw underbar */
1008 sc->hline(i - pm->text_w, i, pm->main_y + pm->font_h - 1);
1009
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +00001010 if (pm->line_edit)
1011 {
1012 sc->set_drawmode(DRMODE_COMPLEMENT);
1013 sc->fillrect(0, y + 2, sc_w, pm->font_h + 2);
1014 sc->set_drawmode(DRMODE_SOLID);
1015 }
Teruaki Kawashimab1a6c902010-02-04 14:53:45 +00001016}
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001017
Teruaki Kawashima1a3b93c2010-06-27 14:03:59 +00001018#ifdef HAVE_TOUCHSCREEN
1019static void kbd_draw_buttons(struct keyboard_parameters *pm, struct screen *sc)
1020{
1021 struct viewport vp;
1022 int button_h, text_h, text_y;
1023 int sc_w = sc->getwidth(), sc_h = sc->getheight();
1024 viewport_set_defaults(&vp, sc->screen_type);
1025 vp.flags |= VP_FLAG_ALIGN_CENTER;
1026 sc->set_viewport(&vp);
1027 text_h = sc->getcharheight();
1028 button_h = GRID_SIZE(sc->screen_type, text_h);
1029 text_y = (button_h - text_h) / 2 + 1;
1030 vp.x = 0;
1031 vp.y = 0;
1032 vp.width = sc_w;
1033 vp.height = button_h;
1034 /* draw buttons */
1035 if (pm->pages > 1)
1036 {
1037 /* button to flip page. */
1038 vp.y = pm->lines*pm->font_h;
1039 sc->hline(0, sc_w - 1, 0);
1040 sc->putsxy(0, text_y, ">");
1041 }
1042 /* OK/Del/Cancel buttons */
1043 button_h = MAX(MIN_GRID_SIZE*2, button_h);
1044 text_y = (button_h - text_h) / 2 + 1;
1045 vp.y = sc_h - button_h - 1;
1046 vp.height = button_h;
1047 sc->hline(0, sc_w - 1, 0);
1048 vp.width = sc_w/3;
1049 sc->putsxy(0, text_y, str(LANG_KBD_OK));
1050 vp.x += vp.width;
1051 sc->vline(0, 0, button_h);
1052 sc->putsxy(0, text_y, str(LANG_KBD_DELETE));
1053 vp.x += vp.width;
1054 sc->vline(0, 0, button_h);
1055 sc->putsxy(0, text_y, str(LANG_KBD_CANCEL));
1056 sc->set_viewport(NULL);
1057}
1058
1059static int keyboard_touchscreen(struct keyboard_parameters *pm,
1060 struct screen *sc, struct edit_state *state)
1061{
1062 short x, y;
1063 const int button = action_get_touchscreen_press(&x, &y);
1064 const int sc_w = sc->getwidth(), sc_h = sc->getheight();
1065 int button_h = MAX(MIN_GRID_SIZE*2, sc->getcharheight());
1066#ifdef HAVE_MORSE_INPUT
1067 if (state->morse_mode && y < pm->main_y - pm->keyboard_margin)
1068 {
1069 /* don't return ACTION_NONE since it has effect in morse mode. */
1070 return button == BUTTON_TOUCHSCREEN? ACTION_KBD_SELECT:
1071 button & BUTTON_REL? ACTION_KBD_MORSE_SELECT: ACTION_STD_OK;
1072 }
1073#else
1074 (void) state;
1075#endif
1076 if (x < 0 || y < 0)
1077 return ACTION_NONE;
1078 if (y < pm->lines*pm->font_h)
1079 {
1080 if (x/pm->font_w < pm->max_chars)
1081 {
1082 /* picker area */
1083 state->changed = CHANGED_PICKER;
1084 pm->x = x/pm->font_w;
1085 pm->y = y/pm->font_h;
1086 pm->line_edit = false;
1087 if (button == BUTTON_REL)
1088 return ACTION_KBD_SELECT;
1089 }
1090 }
1091 else if (y < pm->main_y - pm->keyboard_margin)
1092 {
1093 /* button to flip page */
1094 if (button == BUTTON_REL)
1095 return ACTION_KBD_PAGE_FLIP;
1096 }
1097 else if (y < sc_h - button_h)
1098 {
1099 /* edit line */
1100 if (button & (BUTTON_REPEAT|BUTTON_REL))
1101 {
1102 if (x < sc_w/2)
1103 return ACTION_KBD_CURSOR_LEFT;
1104 else
1105 return ACTION_KBD_CURSOR_RIGHT;
1106 }
1107 }
1108 else
1109 {
1110 /* OK/Del/Cancel button */
1111 if (button == BUTTON_REL)
1112 {
1113 if (x < sc_w/3)
1114 return ACTION_KBD_DONE;
1115 else if (x < (sc_w/3) * 2)
1116 return ACTION_KBD_BACKSPACE;
1117 else
1118 return ACTION_KBD_ABORT;
1119 }
1120 }
1121 return ACTION_NONE;
1122}
1123#endif
1124
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001125/* inserts the selected char */
1126static void kbd_insert_selected(struct keyboard_parameters *pm,
1127 struct edit_state *state)
1128{
1129 /* find input char */
Teruaki Kawashima3d29faa2010-07-10 13:09:39 +00001130 unsigned short ch = get_kbd_ch(pm, pm->x, pm->y);
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001131
1132 /* check for hangul input */
1133 if (ch >= 0x3131 && ch <= 0x3163)
1134 {
1135 unsigned short tmp;
1136
1137 if (!state->hangul)
1138 {
1139 state->hlead = state->hvowel = state->htail = 0;
1140 state->hangul = true;
1141 }
1142
1143 if (!state->hvowel)
1144 {
1145 state->hvowel = ch;
1146 }
1147 else if (!state->htail)
1148 {
1149 state->htail = ch;
1150 }
1151 else
1152 {
1153 /* previous hangul complete */
1154 /* check whether tail is actually lead of next char */
1155 tmp = hangul_join(state->htail, ch, 0);
1156
1157 if (tmp != 0xfffd)
1158 {
1159 tmp = hangul_join(state->hlead, state->hvowel, 0);
1160 kbd_delchar(state);
1161 kbd_inschar(state, tmp);
1162 /* insert dummy char */
1163 kbd_inschar(state, ' ');
1164 state->hlead = state->htail;
1165 state->hvowel = ch;
1166 state->htail = 0;
1167 }
1168 else
1169 {
1170 state->hvowel = state->htail = 0;
1171 state->hlead = ch;
1172 }
1173 }
1174
1175 /* combine into hangul */
1176 tmp = hangul_join(state->hlead, state->hvowel, state->htail);
1177
1178 if (tmp != 0xfffd)
1179 {
1180 kbd_delchar(state);
1181 ch = tmp;
1182 }
1183 else
1184 {
1185 state->hvowel = state->htail = 0;
1186 state->hlead = ch;
1187 }
1188 }
1189 else
1190 {
1191 state->hangul = false;
1192 }
1193
1194 /* insert char */
1195 kbd_inschar(state, ch);
1196}
1197
1198static void kbd_backspace(struct edit_state *state)
1199{
1200 unsigned short ch;
1201 if (state->hangul)
1202 {
1203 if (state->htail)
1204 state->htail = 0;
1205 else if (state->hvowel)
1206 state->hvowel = 0;
1207 else
1208 state->hangul = false;
1209 }
1210
1211 kbd_delchar(state);
1212
1213 if (state->hangul)
1214 {
1215 if (state->hvowel)
1216 ch = hangul_join(state->hlead, state->hvowel, state->htail);
1217 else
1218 ch = state->hlead;
1219 kbd_inschar(state, ch);
1220 }
1221}
1222
1223static void kbd_move_cursor(struct edit_state *state, int dir)
1224{
1225 state->hangul = false;
1226 state->editpos += dir;
1227
1228 if (state->editpos >= 0 && state->editpos <= state->len_utf8)
1229 {
1230 state->changed = CHANGED_CURSOR;
1231 }
Roman1fa3f592013-07-05 20:05:55 +07001232 else if (state->editpos > state->len_utf8)
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001233 {
Roman1fa3f592013-07-05 20:05:55 +07001234 state->editpos = 0;
1235 #if CONFIG_CODEC == SWCODEC
1236 if (global_settings.talk_menu) beep_play(1000, 150, 1500);
1237 #endif
1238 }
1239 else if (state->editpos < 0)
1240 {
1241 state->editpos = state->len_utf8;
1242 #if CONFIG_CODEC == SWCODEC
1243 if (global_settings.talk_menu) beep_play(1000, 150, 1500);
1244 #endif
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001245 }
1246}
1247
Teruaki Kawashima89033392010-06-09 12:08:25 +00001248static void kbd_move_picker_horizontal(struct keyboard_parameters *pm,
1249 struct edit_state *state, int dir)
1250{
1251 state->changed = CHANGED_PICKER;
1252
1253 pm->x += dir;
1254 if (pm->x < 0)
1255 {
1256 if (--pm->page < 0)
1257 pm->page = pm->pages - 1;
1258 pm->x = pm->max_chars - 1;
1259 }
1260 else if (pm->x >= pm->max_chars)
1261 {
1262 if (++pm->page >= pm->pages)
1263 pm->page = 0;
1264 pm->x = 0;
1265 }
1266}
1267
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001268static void kbd_move_picker_vertical(struct keyboard_parameters *pm,
1269 struct edit_state *state, int dir)
1270{
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001271 state->changed = CHANGED_PICKER;
Teruaki Kawashima89033392010-06-09 12:08:25 +00001272
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001273#ifdef HAVE_MORSE_INPUT
1274 if (state->morse_mode)
1275 {
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001276 pm->line_edit = !pm->line_edit;
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001277 return;
1278 }
1279#endif /* HAVE_MORSE_INPUT */
Teruaki Kawashima89033392010-06-09 12:08:25 +00001280
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001281 pm->y += dir;
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001282 if (pm->line_edit)
1283 {
1284 pm->y = (dir > 0 ? 0 : pm->lines - 1);
1285 pm->line_edit = false;
1286 }
1287 else if (pm->y < 0 || pm->y >= pm->lines)
1288 {
1289 pm->line_edit = true;
1290 }
Teruaki Kawashima62e6a2f2010-02-25 06:40:36 +00001291}