/*
	MiniMemo v1.0
*/

#include 	<sys/bios.h>
#include	<stdio.h>
#include 	<fcntl.h>
#include	<stdlib.h>
#include	<string.h>

#include	"rome_tbl.h"

#define		KEY_B0	(0xB0)
#define		KEY_B1	(0xB1)
#define		KEY_B2	(0xB2)
#define		KEY_B3	(0xB3)
#define		KEY_B4	(0xB4)
#define		KEY_B5	(0xB5)
#define		KEY_B6	(0xB6)
#define		KEY_B7	(0xB7)
#define		KEY_B8	(0xB8)
#define		KEY_B9	(0xB9)
#define		KEY_BA	(0xBA)
#define		KEY_BB	(0xBB)
#define		KEY_BC	(0xBC)
#define		KEY_BD	(0xBD)
#define		KEY_BE	(0xBE)
#define		KEY_BF	(0xBF)

#define		KEY_0	(0)
#define		KEY_1	(1)
#define		KEY_2	(2)
#define		KEY_3	(3)
#define		KEY_4	(4)
#define		KEY_5	(5)
#define		KEY_6	(6)
#define		KEY_7	(7)
#define		KEY_8	(8)
#define		KEY_9	(9)
#define		KEY_10	(10)
#define		KEY_11	(11)
#define		KEY_12	(12)
#define		KEY_13	(13)
#define		KEY_14	(14)
#define		KEY_15	(15)

/*
英/カタカナ/ひらがな
	[U  ][I  ][A  ][SP ]
	  4    3    2    0
	[E  ][KGC][SZF][TDJ]
	  5    7    8    9
	[O  ][NLQ][HPB][MV~]
	  6   10   11   12
	[BS ][YX-][R?!][W.,]
	  1   13   14   15

数字
	[ 7 ][ 8 ][ 9 ][SP ]
	  4    3    2    0
	[ 4 ][ 5 ][ 6 ][ \ ]
	  5    7    8    9
	[ 1 ][ 2 ][ 3 ][ $ ]
	  6   10   11   12
	[BS ][ 0 ][ @ ][ # ]
	  1   13   14   15

記号
	[=| ][^~ ]["' ][SP ]
	  4    3    2    0
	[+- ][* /][\$ ][@# ]
	  5    7    8    9
	[() ][[] ][{} ][<> ]
	  6   10   11   12
	[BS ][;: ][., ][!? ]
	  1   13   14   15

	Y1 - 挿入/上書モード切換
	Y2 - メニュー
	Y3 - 入力モード切換
	Y4 - DELETE

	X1 - カーソル↑
	X2 - カーソル→
	X3 - カーソル↓
	X4 - カーソル←
*/

extern	int		unfix_len;

/* ========================================================================= */

#define BUF_SIZE	256					/* シリアル通信バッファサイズ */

static char		recv_buf[BUF_SIZE];		/* 受信バッファ */
static int		recv_s = 0;				/* 受信バッファ中の書き込み位置 */
static int		recv_g = 0;				/* 受信バッファ中の読み出し位置 */
static int		recv_byte = 0;			/* 受信バイト数 */
static int		recv_err = 0;			/* 受信エラーバイト数 */
static int		default_baud;			/* システム通信速度 */

/*
	シリアル受信割り込み処理
*/
void far rx_interrupt(void)
{
	int		rc;

	switch((rc = comm_receive_char()))
	{
		case ERR_SIO_TIMEOUT:
			break;
		case ERR_SIO_CANCEL:
		case ERR_SIO_OVERRUN:
			recv_err++;
			break;
		default:
			if(recv_byte < BUF_SIZE)
			{
				recv_buf[recv_s++] = (char)rc;
				if(recv_s > BUF_SIZE) recv_s = 0;
				recv_byte++;
			}
	}
}

/*
	受信文字数
*/
int rx_len(void)
{
	return recv_byte;
}

/*
	受信バッファから１文字取得
*/
int rx_getchar(void)
{
	int		c;

	if(recv_byte == 0) return -1;
	c = recv_buf[recv_g++];
	if(recv_g > BUF_SIZE) recv_g = 0;
	recv_byte--;
	return c;
}

/*
	シリアル通信開始
*/
void comm_start(int baud)
{
	static intvector_t 	iv;

	recv_s = 0;
	recv_g = 0;
	recv_byte = 0;
	recv_err = 0;

	default_baud = comm_get_baudrate();
	comm_set_baudrate(baud);
	comm_open();
	comm_set_timeout(0,1);

	/*
		割り込みフックを設定
	*/
	iv.callback = (void (near *)())FP_OFF(rx_interrupt);
	iv.cs =  _asm_inline("mov ax, cs");
	iv.ds =  _asm_inline("mov ax, ds");
	sys_interrupt_set_hook(SYS_INT_RECEIVEREADY, &iv, NULL);
}

/*
	シリアル通信終了
*/
void comm_stop()
{
	/*
		割り込みフックを解除
	*/
	sys_interrupt_reset_hook(SYS_INT_RECEIVEREADY, NULL);

	comm_close();
	comm_set_baudrate(default_baud);
}

/* ========================================================================= */

static int	page_buf[10][17][28];	/* ページバッファ */
static int	copy_buf[28];
static BOOL	in_copy = FALSE;

/*
	メモファイル読み込み
*/
BOOL read_memo()
{
	static char	fname[30];
	int			fd;

	/*
		ページバッファをクリア
	*/
	memset(page_buf, 0, sizeof(page_buf));

	/*
		メモファイルを読み込む。無かったら作る
	*/
	strcpy(fname, "/ram0/mmemo.dat");
	if((fd = open(fname, O_RDONLY, 0)) < 0)
	{
		if(creat(fname, FMODE_R|FMODE_W, sizeof(page_buf) / 128 + 1)
			== E_FS_SUCCESS)
		{
			fs_setinfo(fname, "ミニメモデータ");
			return TRUE;
		}
		return FALSE;
	}
	else
	{
		if(read(fd, (char *)page_buf, sizeof(page_buf)) < 0)
		{
			close(fd);
			return FALSE;
		}
		close(fd);
    }

	return TRUE;
}

/*
	メモファイル書き出し
*/
BOOL write_memo()
{
	static char	fname[30];
	int			fd;

	strcpy(fname, "/ram0/mmemo.dat");
	if((fd = open(fname, O_WRONLY, 0)) >= 0)
	{
		if(write(fd, (char *)page_buf, sizeof(page_buf)) < 0)
		{
			close(fd);
			return FALSE;
		}
		close(fd);
		return TRUE;
	}
	return FALSE;
}

/* ========================================================================= */

#define		HIDE_TIME	50				/* カーソル点時間 */
#define		SHOW_TIME	50				/* カーソル滅時間 */

static char		line_buf[60];			/* 行バッファ */
static int		cur_page;				/* 表示ページ */
static int		cur_x = 0;				/* カーソル位置 */
static int		cur_y = 0;
static BOOL		cur_show = TRUE;		/* カーソル表示状態 */
static BOOL		cur_hide = FALSE;		/* カーソル表示禁止 */
static int		cur_blink;				/* カーソル点滅用カウンタ */

/*
	カーソル表示
*/
void cur_on()
{
	if(!cur_hide)
	{
		font_set_color(0x0c);	/* 反転 */
		text_put_char(cur_x, cur_y + 1, page_buf[cur_page][cur_y][cur_x]);
		font_set_color(0x03);	/* 通常 */
		cur_show = TRUE;
	}
}

/*
	カーソル消去
*/
void cur_off()
{
	if(!cur_hide)
	{
		font_set_color(0x03);	/* 通常 */
		text_put_char(cur_x, cur_y + 1, page_buf[cur_page][cur_y][cur_x]);
		cur_show = FALSE;
	}
}

/*
	カーソル表示許可
*/
void show_cursor()
{
	cur_hide = FALSE;
	cur_on();
}

/*
	カーソル表示禁止
*/
void hide_cursor()
{
	cur_off();
	cur_hide = TRUE;
}

/*
	カーソル移動
*/
void move_cursor(int cx, int cy)
{
	if(!cur_hide)
	{
		text_put_char(cur_x, cur_y + 1, page_buf[cur_page][cur_y][cur_x]);
		font_set_color(0x0c);	/* 反転 */
		text_put_char(cx, cy + 1, page_buf[cur_page][cy][cx]);
		font_set_color(0x03);	/* 通常 */
	}
	cur_x = cx;
	cur_y = cy;
	cur_show = TRUE;
	cur_blink = SHOW_TIME;
}

/*
	カーソル点滅
*/
void blink_cursor()
{
	if(!cur_hide)
	{
		if(--cur_blink <= 0)
		{
			if(cur_show)
			{
				cur_off();
				cur_blink = HIDE_TIME;
			}
			else
			{
				cur_on();
				cur_blink = SHOW_TIME;
			}
		}
	}
}

/*
	カーソル↑
*/
void cur_up()
{
	if(cur_y > 0) move_cursor(cur_x, cur_y - 1);
}

/*
	カーソル→
*/
void cur_right()
{
	if(cur_x < 27)
	{
		move_cursor(cur_x + 1, cur_y);
	}
	else
	{
		if(cur_y < 16) move_cursor(0, cur_y + 1);
	}
}

/*
	カーソル↓
*/
void cur_down()
{
	if(cur_y < 16) move_cursor(cur_x, cur_y + 1);
}

/*
	カーソル←
*/
void cur_left()
{
	if(cur_x > 0)
	{
		move_cursor(cur_x - 1, cur_y);
	}
	else
	{
		if(cur_y > 0) move_cursor(27, cur_y - 1);
	}
}

/*
	ページ表示
*/
void disp_page(int page_no)
{
	int				y, i, *pp;
	unsigned int	c;
	char			*lp;

	pp = (int *)page_buf[page_no];
	for(y = 0; y < 17; y++)
	{
		lp = line_buf;
		for(i = 0; i < 28; i++)
		{
			c = *pp++;
			if(c < 256)
			{
				if(c == 0) c = 0x20;
				*lp++ = (char)(c & 255);
			}
			else
			{
				*lp++ = (char)(c >> 8);
				*lp++ = (char)(c & 255);
			}
		}
		*lp = '\0';
		text_put_string(0, y + 1, line_buf);
	}
	cur_page = page_no;
	font_set_color(0x0c);	/* 反転 */
	text_put_numeric(26, 0, 2, NUM_PADZERO, cur_page + 1);	/* ページ番号 */
	font_set_color(0x03);	/* 通常 */
	cur_on();
	cur_blink = SHOW_TIME;
}

/*
	指定位置の文字列表示
*/
void disp_str(int x, int y, int len)
{
	int				i, *pp;
	unsigned int	c;
	char			*lp;

	pp = (int *)&page_buf[cur_page][y][x];
	lp = line_buf;
	for(i = 0; i < len; i++)
	{
		c = *pp++;
		if(c < 256)
		{
			if(c == 0) c = 0x20;
			*lp++ = (char)(c & 255);
		}
		else
		{
			*lp++ = (char)(c >> 8);
			*lp++ = (char)(c & 255);
		}
	}
	*lp = '\0';
	text_put_string(x, y + 1, line_buf);
}

/*
	指定範囲の文字列表示
*/
void disp_area(int x, int y, int w, int h)
{
	int		i;

	for(i = 0; i < h; i++)
	{
		disp_str(x, y + i, w);
	}
}

/*
	カーソル位置に文字を挿入
*/
void insert_char(int c)
{
	int		w;

	w = 27 - cur_x;
	if(w > 0)
	{
		memcpy(line_buf, &page_buf[cur_page][cur_y][cur_x], w * 2);
		memcpy(&page_buf[cur_page][cur_y][cur_x + 1], line_buf, w * 2);
	}
	page_buf[cur_page][cur_y][cur_x] = c;
	disp_str(cur_x, cur_y, w + 1);
	cur_right();
}

/*
	カーソル位置に文字を上書き
*/
void overwrite_char(int c)
{
	page_buf[cur_page][cur_y][cur_x] = c;
	disp_str(cur_x, cur_y, 1);
	cur_right();
}

/*
	カーソル位置の文字を削除
*/
void delete_char()
{
	int		w;

	w = 27 - cur_x;
	if(w > 0)
	{
		memcpy(line_buf, &page_buf[cur_page][cur_y][cur_x + 1], w * 2);
		memcpy(&page_buf[cur_page][cur_y][cur_x], line_buf, w * 2);
	}
	page_buf[cur_page][cur_y][27] = '\0';
	disp_str(cur_x, cur_y, w + 1);
	show_cursor();
}

/*
	バックスペース
*/
void backspace()
{
	if(cur_x > 0)
	{
		cur_left();
		delete_char();
	}
}

/* ========================================================================= */

#define		MODE_UPPER	(0)		/* ASCII    [Ａ] */
#define		MODE_LOWER	(1)		/* ASCII    [ａ] */
#define		MODE_HIRA	(2)		/* ひらがな [あ] */
#define		MODE_KATA	(3)		/* カタカナ [ア] */
#define		MODE_NUM	(4)		/* 数字     [数] */
#define		MODE_SYMBOL	(5)		/* 記号     [記] */

#define		INSERT		(0)		/* 挿入 */
#define		OVERWRITE	(1)		/* 上書き */

#define		INSERT_POS	(15)	/* 挿入/上書きインジケータ位置 */
#define		MODE_POS	(18)	/* 入力モードインジケータ位置 */

static char	*insert_disp[2] = { "挿", "上" };
static char	*mode_disp[6]   = { "Ａ", "ａ", "あ", "ア", "数", "記" };

static int	vowel_tbl[5] = {
				'A', 'I', 'U', 'E', 'O'
			};

static int	conso_tbl[9][3] = {
				'K', 'G', 'C', 'S', 'Z', 'F', 'T', 'D', 'J',
				'N', 'L', 'Q', 'H', 'B', 'P', 'M', 'V', '~',
				'Y', 'X', '-', 'R', '?', '!', 'W', '.', ','
			};

static int	num_tbl[16] = {
				' ', ' ', '9', '8', '7', '4', '1', '5',
				'6', '\\', '2', '3', '$', '0', '@', '#'
			};

static int	symbol_tbl[14][2] = {
				'"', 0x27,
				'^', '~',
				'=', '|',
				'+', '-',
				'(', ')',
				'*', '/',
				'\\', '$',
				'@', '#',
				'[', ']',
				'{', '}',
				'<', '>',
				';', ':',
				'.', ',',
				'!', '?'
			};

static int	input_mode = MODE_UPPER;		/* 入力モード */
static int	insert_mode = INSERT;			/* 挿入/上書きモード */
static char	unfix_buf[20];					/* 未確定文字バッファ */
static int	unfix_len = 0;					/* 未確定文字数 */
static int	unfix_prev = 0;					/* 一つ前の入力キー */
static int	unfix_shift = 0;				/* キーシフト */

/*
	上書きモード変更
*/
void insert_change()
{
	insert_mode++;
	if(insert_mode > OVERWRITE)
	{
		insert_mode = INSERT;
	}
	font_set_color(0x0c);	/* 反転 */
	text_put_string(INSERT_POS, 0, insert_disp[insert_mode]);
	font_set_color(0x03);	/* 通常 */
}

/*
	入力モード変更
*/
void mode_change()
{
	input_mode++;
	if(input_mode > MODE_SYMBOL)
	{
		input_mode = MODE_UPPER;
	}
	font_set_color(0x0c);	/* 反転 */
	text_put_string(MODE_POS, 0, mode_disp[input_mode]);
	font_set_color(0x03);	/* 通常 */
}

/*
	一文字挿入
*/
void set_char(int c)
{
	if(insert_mode == INSERT)
	{
		insert_char(c);
	}
	else
	{
		overwrite_char(c);
	}
}

/*
	かな文字列挿入
*/
void set_kanastring(char *s)
{
	int		i, len;
	int		c;

	if(input_mode == MODE_KATA)
	{
		if(strncmp(s, "う゛", 4) == 0)
		{
			set_char(0x8394);	/* ヴ */
			s += 4;
		}
	}

	len = strlen(s) / 2;
	for(i = 0; i < len; i++)
	{
		c = (*s << 8)|(*(s + 1));
		if((input_mode == MODE_KATA)&&(c >= 0x829F))
		{
			if(c <= 0x82DD)
			{
				c += 0xA1;		/* ひらがな->カタカナ(0x829F〜0x82DD) */
			}
			else
			{
				c += 0xA2;		/* ひらがな->カタカナ(0x82DE〜0x82F1) */
			}
		}
		set_char(c);
		s += 2;
	}
}

/*
	未確定バッファから行バッファへ
*/
void set_linebuf()
{
	memcpy(line_buf, unfix_buf, unfix_len);
	*(line_buf + unfix_len) = '\0';
}

/*
	未確定バッファを表示
*/
void disp_unfix()
{
	int		x;

	if(unfix_len > 0)
	{
		set_linebuf();
		x = (unfix_len + cur_x <= 28) ?
				cur_x : 28 - unfix_len;		/* 位置補正 */
		font_set_color(0x0c);	/* 反転 */
		text_put_string(x, cur_y + 1, line_buf);
		font_set_color(0x03);	/* 通常 */
	}
}

/*
	未確定バッファを隠す
*/
void hide_unfix()
{
	int		x;

	if(unfix_len > 0)
	{
		x = (cur_x + unfix_len <= 28) ?
				cur_x : 28 - unfix_len;	/* 位置補正 */
		disp_str(x, cur_y, unfix_len);
	}
}

/*
	取消
*/
void clear_unfix()
{
	if(unfix_len > 0)
	{
		hide_unfix();
		unfix_len = 0;
		show_cursor();
	}
}

/*
	確定
*/
void flash_unfix()
{
	int		i;

	if(unfix_len > 0)
	{
		hide_unfix();
		for(i = 0; i < unfix_len; i++)
		{
			set_char((int)unfix_buf[i]);
		}
		unfix_len = 0;
		show_cursor();
	}
}

/*
	キーコードから文字コードに変換
*/
char code_convert(int key, int shift)
{
	int		c;

	switch(input_mode)
	{
		case MODE_HIRA:
		case MODE_KATA:
		case MODE_UPPER:
			c = (key < KEY_7) ? vowel_tbl[key - KEY_2] :
			                    conso_tbl[key - KEY_7][shift];
			break;
		case MODE_LOWER:
			c = ((key < KEY_7) ? vowel_tbl[key - KEY_2] :
			                     conso_tbl[key - KEY_7][shift]) + 0x20;
			break;
		case MODE_NUM:
			c = num_tbl[key];
			break;
		case MODE_SYMBOL:
			c = symbol_tbl[key - KEY_2][shift];
			break;
	}
	return c;
}

/*
	未確定文字バッファに挿入
*/
void insert_unfix(int key)
{
	if(unfix_len > 0)
	{
		/*
			未確定文字有り
		*/
		if(unfix_prev == key)
		{
			/*
				未確定文字と同一キー入力
			*/
			unfix_shift++;		/* 表示シフト */
			if(unfix_shift > 2)
			{
				unfix_shift = 0;
			}
			unfix_buf[unfix_len - 1] = code_convert(key, unfix_shift);
			disp_unfix();
		}
		else
		{
			/*
				未確定文字と異なるキー入力
			*/
			flash_unfix();
		}
	}
}

/*
	未確定文字バッファに最初の一文字を格納
*/
void set_unfix(int key)
{
	unfix_buf[0] = code_convert(key, 0);
	unfix_prev = key;
	unfix_len = 1;
	unfix_shift = 0;
}

/*
	未確定文字バッファの内容をシフト
*/
void shift_unfix()
{
	int		i;

	for(i = 1; i < unfix_len; i++)
	{
		unfix_buf[i - 1] = unfix_buf[i];
	}
	unfix_len--;
}

/*
	未確定文字バッファに挿入(ASCIIモード)
*/
void insert_ascii(int key)
{
	if((unfix_len > 0)&&(unfix_prev == key))
	{
		/*
			未確定文字と同じキーなら表示シフト
		*/
		unfix_shift++;
		if(unfix_shift > 2)
		{
			unfix_shift = 0;
		}
		unfix_buf[unfix_len - 1] = code_convert(key, unfix_shift);
		disp_unfix();
	}
	else
	{
		/*
			未確定文字が無い、または未確定文字と異なるキー
		*/
		if(unfix_len > 0)
		{
			/*
				未確定文字有りならバッファ内容を挿入
			*/
			flash_unfix();
		}

		if(key < KEY_7)
		{
			/*
				母音キー
			*/
			set_char(code_convert(key, 0));
		}
		else
		{
			/*
				未確定文字バッファに格納
			*/
			set_unfix(key);
			hide_cursor();
			disp_unfix();
		}
	}
}

/*
	ローマ字テーブルを検索
*/
int kana_search(int no)
{
	struct ROME	*rp;
	int			i;

	rp = tbl_idx[no];
	for(i = 0; i < tbl_idx_size[no]; i++, rp++)
	{
		if(strcmp(line_buf, rp->r) == 0)
		{
			return i;
		}
	}

	return -1;
}

/*
	かな変換
*/
void kana_trans()
{
	struct ROME	*rp;
	int			top, no;

	/*
		未確定文字消去
	*/
	hide_unfix();

	/*
		未確定文字が無くなるか、変換不可になるまでループ
	*/
	while(unfix_len > 0)
	{
		top = (int)unfix_buf[0];	/* 最初の一文字 */
		line_buf[0] = (char)(top & 255);
		line_buf[1] = '\0';
		/*
			一文字テーブルを検索
		*/
		if((no = kana_search(0)) >= 0)
		{
			/*
				一致
			*/
			rp = tbl_idx[0];
			set_kanastring((rp + no)->k);			/* 一文字確定 */
			/*
				一文字シフト
			*/
			shift_unfix();
		}
		else
		{
			/*
				複数文字検索
			*/
			top -= 0x41;
			set_linebuf();
			if((no = kana_search(top)) >= 0)
			{
				/*
					確定
				*/
				rp = tbl_idx[top];
				set_kanastring((rp + no)->k);
				unfix_len = 0;
			}
			else
			if((unfix_buf[0] == 'N')&&(unfix_len > 1))
			{
				/*
					'N' + 子音
				*/
				set_kanastring("ん");
				shift_unfix();
			}
			else
			if((unfix_buf[0] == unfix_buf[1])&&(unfix_len > 1))
			{
				/*
					子音 + 子音
				*/
				set_kanastring("っ");
				shift_unfix();
			}
			else
			{
				break;
			}
		}
	}

	/*
		未確定文字再表示
	*/
	disp_unfix();
}

/*
	未確定文字バッファに挿入(かなモード)
*/
void insert_kana(int key)
{
	if((unfix_len > 0)&&(unfix_prev == key))
	{
		/*
			未確定文字と同じキーなら表示シフト
		*/
		unfix_shift++;
		if(unfix_shift > 2)
		{
			unfix_shift = 0;
		}
		unfix_buf[unfix_len - 1] = code_convert(key, unfix_shift);
		disp_unfix();
	}
	else
	{
		if(unfix_len == 0)
		{
			hide_cursor();
		}

		if(key < KEY_7)
		{
			/*
				既に未確定バッファに入っている文字を変換
			*/
			kana_trans();
			/*
				母音を追加して変換
			*/
			unfix_buf[unfix_len++] = code_convert(key, 0);
			kana_trans();
			unfix_prev = 0;
			unfix_shift = 0;
		}
		else
		{
			/*
				既に未確定バッファに入っている文字を変換
			*/
			kana_trans();
			/*
				未確定バッファに文字追加して表示
			*/
			unfix_buf[unfix_len++] = code_convert(key, 0);
			disp_unfix();
			unfix_prev = key;
			unfix_shift = 0;
		}

		if(unfix_len == 0)
		{
			show_cursor();
		}
	}
}

/*
	未確定文字バッファに挿入(記号モード)
*/
void insert_symbol(int key)
{
	if((unfix_len > 0)&&(unfix_prev == key))
	{
		/*
			未確定文字と同じキーなら表示シフト
		*/
		unfix_shift++;
		if(unfix_shift > 1)
		{
			unfix_shift = 0;
		}
		unfix_buf[unfix_len - 1] = code_convert(key, unfix_shift);
		disp_unfix();
	}
	else
	{
		/*
			未確定文字が無い、または未確定文字と異なるキー
		*/
		if(unfix_len > 0)
		{
			/*
				未確定文字有りならバッファ内容を挿入
			*/
			flash_unfix();
		}

		/*
			未確定文字バッファに格納
		*/
		set_unfix(key);
		hide_cursor();
		disp_unfix();
	}
}

/*
	英字モード
*/
void key_ascii(int key)
{
	switch(key)
	{
		case KEY_0:		/* 確定/SPACE */
			if(unfix_len > 0)
			{
				flash_unfix();
			}
			else
			{
				set_char(0x20);
			}
			break;
		case KEY_1:		/* 取消/BACKSPACE */
			if(unfix_len > 0)
			{
				clear_unfix();
			}
			else
			{
				backspace();
			}
			break;
		default:		/* その他のキー */
			insert_ascii(key);
	}
}

/*
	かなモード
*/
void key_kana(int key)
{
	switch(key)
	{
		case KEY_0:		/* 確定/SPACE */
			if(unfix_len > 0)
			{
				/*
					既に未確定バッファに入っている文字を変換
				*/
				kana_trans();
				unfix_prev = 0;
				unfix_shift = 0;
				if(unfix_len == 0)
				{
					show_cursor();
				}
			}
			else
			{
				set_char(0x20);
			}
			break;
		case KEY_1:		/* 取消/BACKSPACE */
			if(unfix_len > 0)
			{
				clear_unfix();
			}
			else
			{
				backspace();
			}
			break;
		default:		/* その他のキー */
			insert_kana(key);
	}
}

/*
	数字モード
*/
void key_numeric(int key)
{
	switch(key)
	{
		case KEY_0:		/* SPACE */
			set_char(0x20);
			break;
		case KEY_1:		/* BACKSPACE */
			backspace();
			break;
		default:		/* その他のキー */
			set_char(code_convert(key, 0));
	}
}

/*
	記号モード
*/
void key_symbol(int key)
{
	switch(key)
	{
		case KEY_0:		/* 確定/SPACE */
			if(unfix_len > 0)
			{
				flash_unfix();
			}
			else
			{
				set_char(0x20);
			}
			break;
		case KEY_1:		/* 取消/BACKSPACE */
			if(unfix_len > 0)
			{
				clear_unfix();
			}
			else
			{
				backspace();
			}
			break;
		default:		/* その他のキー */
			insert_symbol(key);
	}
}

/*
	拡張キー入力処理
*/
int ex_key_hit(int ex_key)
{
	static int	cc_tbl[16] = {
					 4,  3,  2,  0,
					 5,  7,  8,  9,
					 6, 10, 11, 12,
					 1, 13, 14, 15
				};

	ex_key = cc_tbl[ex_key - 0xB0];		/* 内部キーコードに変換 */
	switch(input_mode)
	{
		case MODE_UPPER:
		case MODE_LOWER:
			key_ascii(ex_key);
			break;
		case MODE_HIRA:
		case MODE_KATA:
			key_kana(ex_key);
			break;
		case MODE_NUM:
			key_numeric(ex_key);
			break;
		case MODE_SYMBOL:
			key_symbol(ex_key);
			break;
	}
}

/* ========================================================================= */

/*
	ページ消去
*/
void page_clear()
{
	memset(&page_buf[cur_page], 0, sizeof(page_buf) / 10);
	disp_page(cur_page);
	cur_on();
	cur_blink = SHOW_TIME;
}

/*
	ライン消去
*/
void line_clear()
{
	memset(&page_buf[cur_page][cur_y], 0, 28 * 2);
	disp_str(0, cur_y, 28);
	cur_on();
	cur_blink = SHOW_TIME;
}

/*
	ラインコピー
*/
void line_copy()
{
	memcpy(copy_buf, &page_buf[cur_page][cur_y], 28 * 2);
	in_copy = TRUE;
}

/*
	ラインペースト
*/
void line_paste()
{
	if(in_copy)
	{
		memcpy(&page_buf[cur_page][cur_y], copy_buf, 28 * 2);
		disp_str(0, cur_y, 28);
		cur_on();
		cur_blink = SHOW_TIME;
	}
}

/*
	ライン挿入
*/
void line_insert()
{
	int		i;

	for(i = 15; i >= cur_y; i--)
	{
		memcpy(&page_buf[cur_page][i + 1], &page_buf[cur_page][i], 28 * 2);
	}
	memset(&page_buf[cur_page][cur_y], 0, 28 * 2);
	disp_page(cur_page);
	cur_on();
	cur_blink = SHOW_TIME;
}

/*
	ライン削除
*/
void line_delete()
{
	if(cur_y < 16)
	{
		memcpy(&page_buf[cur_page][cur_y],
			   &page_buf[cur_page][cur_y + 1], 28 * 2 * (16 - cur_y));
	}
	memset(&page_buf[cur_page][16], 0, 28 * 2);
	disp_page(cur_page);
	cur_on();
	cur_blink = SHOW_TIME;
}

/* ========================================================================= */

#define		MENU_LINECOPY	(0)
#define		MENU_LINEPASTE	(1)
#define		MENU_LINECLR	(2)
#define		MENU_LINEINS	(3)
#define		MENU_LINEDEL	(4)
#define		MENU_PAGECLR	(5)

#define		EXIT_SAVE		(0)
#define		EXIT_NOSAVE		(1)

static char	*main_menu[] = {
				"行複写",
				"行貼付",
				"行消去",
				"行挿入",
				"行削除",
				"頁消去"
			};

static char	*exit_menu[] = {
				"保存して終了",
				"破棄して終了",
			};

static	int		menu_x, menu_y, menu_w, menu_n;
static	int		menu_c;
static	char	**menu_p;
static	char	menu_buf[40];

/*
	メニュー選択カーソル表示
*/
void show_select(int n)
{
	strcpy(menu_buf, " ");
	strcat(menu_buf, *(menu_p + n));
	strcat(menu_buf, " ");
	font_set_color(0x0c);	/* 反転 */
	text_put_string(menu_x + 1, menu_y + n + 2, menu_buf);
	font_set_color(0x03);	/* 通常 */
}

/*
	メニュー選択カーソル消去
*/
void hide_select(int n)
{
	strcpy(menu_buf, " ");
	strcat(menu_buf, *(menu_p + n));
	strcat(menu_buf, " ");
	font_set_color(0x03);	/* 通常 */
	text_put_string(menu_x + 1, menu_y + n + 2, menu_buf);
}

/*
	メニュー表示
*/
void show_menu(char **m, int x, int y, int w, int n)
{
	int		i;

	y++;
	strcpy(menu_buf, "┏");
	for(i = 0; i < w + 2; i++) strcat(menu_buf, "━");
	strcat(menu_buf, "┓");
	text_put_string(x, y, menu_buf);
	for(i = 0; i < n; i++)
	{
		strcpy(menu_buf, "┃ ");
		strcat(menu_buf, *(m + i));
		strcat(menu_buf, " ┃");
		text_put_string(x, y + i + 1, menu_buf);
	}
	strcpy(menu_buf, "┗");
	for(i = 0; i < w + 2; i++) strcat(menu_buf, "━");
	strcat(menu_buf, "┛");
	text_put_string(x, y + n + 1, menu_buf);
}

/*
	メニュー消去
*/
void hide_menu(int x, int y, int w, int n)
{
	disp_area(x, y, w + 4, n + 2);
}

/*
	メニュー選択
*/
int menu_select(char **m, int x, int y, int n)
{
	int		ws_key, ex_key;
	int		w, s, ret;
	BOOL	done = FALSE;

	menu_p = m;
	menu_x = x;
	menu_y = y;

	w = strlen(*m) / 2;
	show_menu(m, x, y, w, n);
	show_select(0);
	s = 0;
	while(!done)
	{
		/*
			スワンのキー入力処理
		*/
		ws_key = key_hit_check_with_repeat();
		if(ws_key)
		{
			if(ws_key & KEY_A)
			{
				done = TRUE;
				ret = s;
				continue;
			}
			else
			if(ws_key & KEY_UP1)
			{
				if(s > 0)
				{
					hide_select(s--);
					show_select(s);
				}
				continue;
			}
			else
			if(ws_key & KEY_DOWN1)
			{
				if(s < n - 1)
				{
					hide_select(s++);
					show_select(s);
				}
				continue;
			}
			else
			if(ws_key & KEY_B)
			{
				done = TRUE;
				ret = -1;
				continue;
			}
		}

		/*
			HandyKeyのキー入力処理
		*/
		if(rx_len() > 0)
		{
			ex_key = rx_getchar();
			if(ex_key == KEY_B3)
			{
				done = TRUE;
				ret = s;
				continue;
			}
			else
			if(ex_key == KEY_BC)
			{
				done = TRUE;
				ret = -1;
				continue;
			}
		}
	}

	hide_menu(x, y, w, n);
	return ret;
}

void menu()
{
	int		sel;

	sel = menu_select(main_menu, 0, 0, sizeof(main_menu) / 2);
	switch(sel)
	{
		case -1:
			return;
		case MENU_PAGECLR:
			page_clear();
			break;
		case MENU_LINECLR:
			line_clear();
			break;
		case MENU_LINECOPY:
			line_copy();
			break;
		case MENU_LINEPASTE:
			line_paste();
			break;
		case MENU_LINEINS:
			line_insert();
			break;
		case MENU_LINEDEL:
			line_delete();
			break;
	}
}

/* ========================================================================= */

/*
	初期化処理
*/
void init()
{
	display_control(DCM_SCR1|DCM_SCR2|DCM_SPR);
    text_screen_init();
	font_set_color(0x0c);	/* 反転 */
	text_put_string(0, 0, "MiniMemo      [挿][Ａ] Page 01");
	font_set_color(0x03);	/* 通常 */

	comm_start(COMM_SPEED_38400);
}

/*
	終了処理
*/
void clean_up()
{
	comm_stop();
}

/*
	スワンキー入力処理
*/
void ws_key_hit(int ws_key)
{
	if(unfix_len == 0)
	{
		if(ws_key & KEY_X1)
		{
			cur_up();
		}
		else
		if(ws_key & KEY_X2)
		{
			cur_right();
		}
		else
		if(ws_key & KEY_X3)
		{
			cur_down();
		}
		else
		if(ws_key & KEY_X4)
		{
			cur_left();
		}
		else
		if(ws_key & KEY_Y2)
		{
			menu();
		}
		else
		if(ws_key & KEY_Y3)
		{
			mode_change();
		}
		else
		if(ws_key & KEY_A)
		{
			if(cur_page < 9)
			{
				disp_page(cur_page + 1);
			}
		}
		else
		if(ws_key & KEY_B)
		{
			if(cur_page > 0)
			{
				disp_page(cur_page - 1);
			}
		}
	}

	if(ws_key & KEY_Y1)
	{
		insert_change();
	}

	if(ws_key & KEY_Y4)
	{
		if(unfix_len == 0)
		{
			delete_char();
		}
		else
		{
			hide_unfix();
			unfix_len--;
			if(unfix_len > 0)
			{
				disp_unfix();
			}
			else
			{
				show_cursor();
			}
		}
	}
}

/*
	メイン
*/
void main(int argc, char *argv[])
{
	int		ws_key, ex_key, sel;
	BOOL	done = FALSE;

	/*
		初期化処理
	*/
	init();

	/*
		メモファイル読み込み
	*/
	if(!read_memo())
	{
		text_put_string(5,  7, "┏━━━━━━━━━━━━━━━━┓");
		text_put_string(5,  8, "┃　メモファイルが作成できません　┃");
		text_put_string(5,  9, "┗━━━━━━━━━━━━━━━━┛");
		key_wait();
		goto exit_main;
	}
	disp_page(0);

	/*
		メインループ
	*/
	while(!done)
	{
		/*
			スワンのキー入力処理
		*/
		ws_key = key_hit_check_with_repeat();
		if(ws_key)
		{
			if(ws_key & KEY_START)
			{
				/*
					終了メニュー表示
				*/
				sel = menu_select(exit_menu, 9, 6, sizeof(exit_menu) / 2);
				if(sel == -1)
				{
					continue;
				}
				else
				if(sel == EXIT_SAVE)
				{
					/*
						メモファイル保存
					*/
					write_memo();
				}
				done = TRUE;
				continue;
			}
			ws_key_hit(ws_key);
		}

		/*
			HandyKeyのキー入力処理
		*/
		if(rx_len() > 0)
		{
			ex_key = rx_getchar();
			ex_key_hit(ex_key);
		}

		/*
			カーソル点滅
		*/
		blink_cursor();
	}

exit_main:
	/*
		終了処理
	*/
	clean_up();
}
