diff options
Diffstat (limited to 'src-util/input.c')
-rw-r--r-- | src-util/input.c | 1543 |
1 files changed, 1543 insertions, 0 deletions
diff --git a/src-util/input.c b/src-util/input.c new file mode 100644 index 0000000..00c58da --- /dev/null +++ b/src-util/input.c @@ -0,0 +1,1543 @@ +/* + * Anthyのキーの受け付けやプリエディットの制御を行うレイヤー + * + * 今からアプリケーションを書く場合にはuimの利用をお薦めします。 + * + * Funded by IPA未踏ソフトウェア創造事業 2002 1/23 + * Copyright (C) 2001-2002 UGAWA Tomoharu + * + * $Id: input.c,v 1.25 2002/11/16 03:35:21 yusuke Exp $ + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> + +#include <anthy/anthy.h> +#include <anthy/input.h> + +#include "rkconv.h" +#include "rkhelper.h" + +struct anthy_input_context { + /* ANTHY_INPUT_ST_* */ + int state; + + /* always allocated */ + struct rk_conv_context* rkctx; + int map_no; /* RKMAP_* */ + /* 変換する文字列のバッファ*/ + char* hbuf; + int n_hbuf; + int s_hbuf; + char* hbuf_follow; + int n_hbuf_follow; + int s_hbuf_follow; + + /* allocated only in conv state */ + anthy_context_t actx; + struct a_segment* segment; + struct a_segment* cur_segment; + int enum_cand_count; + int enum_cand_limit; + int enum_reverse; + int last_gotten_cand; + + /* always allocated by the library */ + /* コミットバッファ */ + char* commit; + int n_commit; + int s_commit; + + /* always allocated by the library */ + /* カットバッファ */ + char* cut; + int n_cut; + int s_cut; + + struct anthy_input_config* cfg; + struct anthy_input_context* next_cfg_owner; +}; + +int anthy_input_errno; + +#define DEFAULT_ENUM_CAND_LIMIT 3 + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#define is_eucchar(s) (((s)[0] & 0x80) && ((s)[1] & 0x80)) + + +struct anthy_input_config { + struct rk_option* rk_option; + /* 6はsrc-util/rkhelper.h の NR_RKMAPに相当 */ + struct rk_map* rk_map[6]; + struct anthy_input_context* owners; + /**/ + int break_into_roman; + int preedit_mode; +}; + +struct a_segment { + int index; + int pos; + struct anthy_segment_stat ass; + int cand; + struct a_segment* next, * prev; +}; + +static int +ensure_buffer(char** buf, int* size, int to_size) +{ + if (*size < to_size) { + *buf = (char*) realloc(*buf, to_size); + if (*buf == NULL) { + anthy_input_errno = AIE_NOMEM; + return -1; + } + *size = to_size; + } + return 0; +} + +static void +leave_edit_state(struct anthy_input_context* ictx) +{ + /* do noting */ + (void) ictx; +} + + +static void +enter_none_state(struct anthy_input_context* ictx) +{ + ictx->state = ANTHY_INPUT_ST_NONE; +} + +static void +enter_edit_state(struct anthy_input_context* ictx) +{ + ictx->state = ANTHY_INPUT_ST_EDIT; + rk_flush(ictx->rkctx); + rk_select_registered_map(ictx->rkctx, ictx->map_no); + ictx->n_hbuf = 0; + ictx->n_hbuf_follow = 0; +} + +static void +enter_edit_state_noinit(struct anthy_input_context* ictx) +{ + ictx->state = ANTHY_INPUT_ST_EDIT; +} + +static void +leave_conv_state(struct anthy_input_context* ictx) +{ + struct a_segment* as, * next; + anthy_release_context(ictx->actx); + for (as = ictx->segment; as; as = next) { + next = as->next; + free(as); + } + anthy_reset_context(ictx->actx); +} + +static void +reset_anthy_input_context(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + leave_edit_state(ictx); + break; + case ANTHY_INPUT_ST_CONV: + leave_conv_state(ictx); + break; + } + enter_none_state(ictx); +} + +static void +read_rk_result(struct anthy_input_context* ictx) +{ + int ret; + + ret = rk_result(ictx->rkctx, ictx->hbuf + ictx->n_hbuf, + ictx->s_hbuf - ictx->n_hbuf); + if (ret > 0) { + if (ictx->s_hbuf - ictx->n_hbuf > 0) + ictx->n_hbuf = ictx->s_hbuf - 1; + + ensure_buffer(&ictx->hbuf, &ictx->s_hbuf, ictx->n_hbuf + ret + 1); + + rk_result(ictx->rkctx, ictx->hbuf + ictx->n_hbuf, + ictx->s_hbuf - ictx->n_hbuf); + } + if (ictx->hbuf) + ictx->n_hbuf += strlen(ictx->hbuf + ictx->n_hbuf); +} + +static void +terminate_rk(struct anthy_input_context* ictx) +{ + rk_terminate(ictx->rkctx); + read_rk_result(ictx); + rk_flush(ictx->rkctx); +} + +static void +join_noconv_string(struct anthy_input_context* ictx) +{ + if (ictx->n_hbuf_follow > 0) { + ensure_buffer(&ictx->hbuf, &ictx->s_hbuf, + ictx->n_hbuf + ictx->n_hbuf_follow); + memcpy(ictx->hbuf + ictx->n_hbuf, ictx->hbuf_follow, ictx->n_hbuf_follow); + ictx->n_hbuf += ictx->n_hbuf_follow; + ictx->n_hbuf_follow = 0; + } +} + +static void +enter_conv_state(struct anthy_input_context* ictx) +{ + int ret; + struct anthy_conv_stat acs; + struct a_segment* as_tail, ** as_tailp; + int i; + int last_pos; + + ictx->state = ANTHY_INPUT_ST_CONV; + + terminate_rk(ictx); + + join_noconv_string(ictx); + + if (ictx->n_hbuf == 0) { + ensure_buffer(&ictx->commit, &ictx->s_commit, ictx->n_commit + 1); + ictx->commit[ictx->n_commit++] = ' '; + enter_none_state(ictx); + return; + } + + ensure_buffer(&ictx->hbuf, &ictx->s_hbuf, ictx->n_hbuf + 1); + ictx->hbuf[ictx->n_hbuf] = '\0'; + + ictx->enum_cand_count = 0; + ictx->actx = anthy_create_context(); + anthy_context_set_encoding(ictx->actx, ANTHY_EUC_JP_ENCODING); + if (!ictx->actx) { + enter_none_state(ictx); + anthy_input_errno = AIE_NOMEM; + return; + } + anthy_reset_context(ictx->actx); + ret = anthy_set_string(ictx->actx, ictx->hbuf); + if (ret < 0) { + anthy_release_context(ictx->actx); + enter_none_state(ictx); + return; + } + + anthy_get_stat(ictx->actx, &acs); + as_tail = NULL; + as_tailp = &ictx->segment; + last_pos = 0; + for (i = 0; i < acs.nr_segment; i++) { + struct a_segment* as; + as = (struct a_segment*) malloc(sizeof(struct a_segment)); + as->index = i; + as->pos = last_pos; + anthy_get_segment_stat(ictx->actx, i, &as->ass); + last_pos += as->ass.seg_len; + as->cand = 0; + as->prev = as_tail; + *as_tailp = as; + as->next = NULL; + as_tailp = &as->next; + as_tail = as; + } + ictx->cur_segment = ictx->segment; + ictx->last_gotten_cand = 0; +} + +static void +enter_conv_state_noinit(struct anthy_input_context* ictx) +{ + ictx->state = ANTHY_INPUT_ST_CONV; +} + +static void +enter_cseg_state(struct anthy_input_context* ictx) +{ + ictx->state = ANTHY_INPUT_ST_CSEG; + ictx->enum_cand_count = 0; +} + +static void +leave_cseg_state(struct anthy_input_context* ictx) +{ + /* do nothing */ + (void)ictx; +} + +static int +cmdh_map_select(struct anthy_input_context* ictx, int map) +{ + switch (map) { + case ANTHY_INPUT_MAP_ALPHABET: + ictx->map_no = RKMAP_ASCII; + break; + case ANTHY_INPUT_MAP_WALPHABET: + ictx->map_no = RKMAP_WASCII; + break; + case ANTHY_INPUT_MAP_HIRAGANA: + ictx->map_no = RKMAP_HIRAGANA; + break; + case ANTHY_INPUT_MAP_KATAKANA: + ictx->map_no = RKMAP_KATAKANA; + break; + case ANTHY_INPUT_MAP_HANKAKU_KANA: + ictx->map_no = RKMAP_HANKAKU_KANA; + break; + default: + anthy_input_errno = AIE_INVAL; + return -1; + } + + rk_select_registered_map(ictx->rkctx, ictx->map_no); + + return 0; +} + +static struct anthy_input_segment* +cmdh_get_candidate(struct anthy_input_context* ictx, int cand_no) +{ + struct a_segment* cs; + struct anthy_input_segment* seg; + int len; + + cs = ictx->cur_segment; + if (cand_no >= cs->ass.nr_candidate) { + anthy_input_errno = AIE_INVAL; + return NULL; + } + ictx->last_gotten_cand = cand_no; + + seg = (struct anthy_input_segment*) + malloc(sizeof(struct anthy_input_segment)); + len = anthy_get_segment(ictx->actx, cs->index, cand_no, NULL, 0); + seg->str = (char*) malloc(len + 1); + anthy_get_segment(ictx->actx, cs->index, cand_no, seg->str, len + 1); + seg->cand_no = cand_no; + seg->noconv_len = anthy_get_segment(ictx->actx, cs->index, + NTH_UNCONVERTED_CANDIDATE, NULL, 0); + seg->nr_cand = cs->ass.nr_candidate; + seg->flag = ANTHY_INPUT_SF_CURSOR; + if (ictx->enum_cand_count >= ictx->enum_cand_limit) + seg->flag |= (ictx->enum_reverse ? + ANTHY_INPUT_SF_ENUM_REVERSE : ANTHY_INPUT_SF_ENUM); + + return seg; +} + +static void +do_cmd_commit(struct anthy_input_context* ictx) +{ + struct a_segment* as; + + for (as = ictx->segment; as; as = as->next) { + int len; + + len = anthy_get_segment(ictx->actx, as->index, as->cand, NULL, 0); + ensure_buffer(&ictx->commit, &ictx->s_commit, ictx->n_commit + len + 1); + anthy_get_segment(ictx->actx, as->index, as->cand, + ictx->commit + ictx->n_commit, len + 1); + ictx->n_commit += len; + anthy_commit_segment(ictx->actx, as->index, as->cand); + } +} + +static int +cmdh_select_candidate(struct anthy_input_context* ictx, + int cand_no) +{ + struct a_segment* cs; + + cs = ictx->cur_segment; + if (cand_no >= cs->ass.nr_candidate) { + anthy_input_errno = AIE_INVAL; + return -1; + } + cs->cand = cand_no; + + if (cs->next) { + ictx->cur_segment = cs->next; + ictx->last_gotten_cand = ictx->cur_segment->cand; + ictx->enum_cand_count = 0; + } else { + ictx->last_gotten_cand = ictx->cur_segment->cand; + ictx->enum_cand_count = 0; + } + + return 0; +} + +static void +do_cmd_push_key(struct anthy_input_context* ictx, const char* str) +{ + const char* p; + + for (p = str; *p; p++) { + if (isspace((int)(unsigned char) *p) && *p != ' ') + continue; + + rk_push_key(ictx->rkctx, *p); + read_rk_result(ictx); + } +} + +static void +cmd_push_key(struct anthy_input_context* ictx, const char* str) +{ + do_cmd_push_key(ictx, str); +} + +static void +cmd_move_cursor(struct anthy_input_context* ictx, int d) +{ + if (rk_get_pending_str(ictx->rkctx, NULL, 0) > 1) { + rk_flush(ictx->rkctx); + return; + } + + if (d > 0) { + char* p; + int len; + if (ictx->n_hbuf_follow == 0) + return; + for (p = ictx->hbuf_follow; + p < ictx->hbuf_follow + ictx->n_hbuf_follow && d > 0; p++, d--) { + if (p < ictx->hbuf_follow + ictx->n_hbuf_follow - 1 && is_eucchar(p)) + p++; + } + len = p - ictx->hbuf_follow; + ensure_buffer(&ictx->hbuf, &ictx->s_hbuf, ictx->n_hbuf + len); + memcpy(ictx->hbuf + ictx->n_hbuf, ictx->hbuf_follow, len); + ictx->n_hbuf += len; + ictx->n_hbuf_follow -= len; + memmove(ictx->hbuf_follow, p, ictx->n_hbuf_follow); + } else { + char* p; + int len; + if (ictx->n_hbuf == 0) + return; + for (p = ictx->hbuf + ictx->n_hbuf; + p > ictx->hbuf && d < 0; p--, d++) { + if (p - 1 > ictx->hbuf && is_eucchar(p - 2)) + p--; + } + len = (ictx->hbuf + ictx->n_hbuf) - p; + ensure_buffer(&ictx->hbuf_follow, &ictx->s_hbuf_follow, + ictx->n_hbuf_follow + len); + if (ictx->n_hbuf_follow > 0) + memmove(ictx->hbuf_follow + len, ictx->hbuf_follow, ictx->n_hbuf_follow); + memcpy(ictx->hbuf_follow, p, len); + ictx->n_hbuf_follow += len; + ictx->n_hbuf -= len; + } +} + +static void +cmd_backspace(struct anthy_input_context* ictx) +{ + int len; + + len = rk_get_pending_str(ictx->rkctx, NULL, 0); + if (len > 1) { + char* buf; + /* 確定されていないローマ字があるので、最後の文字をカット */ + len--; + + buf = (char*) malloc(len); + rk_get_pending_str(ictx->rkctx, buf, len); + rk_flush(ictx->rkctx); + do_cmd_push_key(ictx, buf); + free(buf); + } else { + if (brk_roman_get_previous_pending(ictx->rkctx)) { + char *buf; + buf = strdup(brk_roman_get_previous_pending(ictx->rkctx)); + ictx->n_hbuf -= brk_roman_get_decided_len(ictx->rkctx); + + rk_flush(ictx->rkctx); + do_cmd_push_key(ictx,buf); + free(buf); + } else { + if (ictx->n_hbuf >= 2 && is_eucchar(ictx->hbuf + ictx->n_hbuf - 2)) { + ictx->n_hbuf -= 2; + } else if (ictx->n_hbuf >= 1) { + ictx->n_hbuf--; + } + } + } + + if (ictx->n_hbuf + ictx->n_hbuf_follow <= 0 && len <= 1) { + leave_edit_state(ictx); + enter_none_state(ictx); + } +} + +static void +cmd_delete(struct anthy_input_context* ictx) +{ + int len; + + if (rk_get_pending_str(ictx->rkctx, NULL, 0) > 1) + return; + if (ictx->n_hbuf_follow <= 0) + return; + + len = ictx->n_hbuf_follow >= 2 && is_eucchar(ictx->hbuf_follow) ? 2 : 1; + + if (ictx->n_hbuf_follow <= len) + ictx->n_hbuf_follow = 0; + else { + ictx->n_hbuf_follow -= len; + memmove(ictx->hbuf_follow, ictx->hbuf_follow + len, ictx->n_hbuf_follow); + } + + if (ictx->n_hbuf + ictx->n_hbuf_follow <= 0) { + leave_edit_state(ictx); + enter_none_state(ictx); + } +} + +static void +cmd_commit_unconv(struct anthy_input_context* ictx) +{ + ensure_buffer(&ictx->commit, &ictx->s_commit, + ictx->n_commit + ictx->n_hbuf + ictx->n_hbuf_follow); + memcpy(ictx->commit + ictx->n_commit, ictx->hbuf, ictx->n_hbuf); + ictx->n_commit += ictx->n_hbuf; + if (ictx->n_hbuf_follow > 0) + memcpy(ictx->commit + ictx->n_commit, + ictx->hbuf_follow, ictx->n_hbuf_follow); + ictx->n_commit += ictx->n_hbuf_follow; +} + +static void +cmd_resize(struct anthy_input_context* ictx, int d) +{ + int i; + struct anthy_conv_stat acs; + struct a_segment* as; + int last_pos; + + anthy_resize_segment(ictx->actx, ictx->cur_segment->index, d); + anthy_get_stat(ictx->actx, &acs); + + anthy_get_segment_stat(ictx->actx, + ictx->cur_segment->index, &ictx->cur_segment->ass); + ictx->cur_segment->cand = NTH_UNCONVERTED_CANDIDATE; + last_pos = ictx->cur_segment->ass.seg_len; + for (as = ictx->cur_segment, i = as->index + 1; i < acs.nr_segment; i++) { + if (as->next == NULL) { + struct a_segment* as2; + + as2 = (struct a_segment*) malloc(sizeof(struct a_segment)); + as2->index = i; + as2->prev = as; + as->next = as2; + as2->next = NULL; + as = as2; + } else + as = as->next; + as->pos = last_pos; + anthy_get_segment_stat(ictx->actx, i, &as->ass); + last_pos += as->ass.seg_len; + as->cand = NTH_UNCONVERTED_CANDIDATE; + } + ictx->last_gotten_cand = NTH_UNCONVERTED_CANDIDATE; + + as = as->next; /* 不正なメモリアクセスの修正 */ + if (as) { + as->prev->next = NULL; + for (; as; ) { + struct a_segment* const next = as->next; + free(as); + as = next; + } + } +} + +static void +commit_noconv_string(struct anthy_input_context* ictx) +{ + join_noconv_string(ictx); + ensure_buffer(&ictx->commit, &ictx->s_commit, + ictx->n_commit + ictx->n_hbuf + 1); + /* +1 is just for an optimization */ + memcpy(ictx->commit + ictx->n_commit, + ictx->hbuf, ictx->n_hbuf); + ictx->n_commit += ictx->n_hbuf; + ictx->n_hbuf = 0; +} + +static void +cmd_commit(struct anthy_input_context* ictx) +{ + do_cmd_commit(ictx); +} + +static void +cmd_next_candidate(struct anthy_input_context* ictx) +{ + struct a_segment* as; + + ictx->enum_cand_count++; + + as = ictx->cur_segment; + + if (!ictx->enum_reverse) + as->cand = ictx->last_gotten_cand; + else + ictx->enum_reverse = 0; + + if (as->cand == NTH_UNCONVERTED_CANDIDATE) { + while (as) { + if (as->cand == NTH_UNCONVERTED_CANDIDATE) { + as->cand = 0; + } + as = as->next; + } + ictx->last_gotten_cand = 0; + } else { + if (++as->cand >= as->ass.nr_candidate) + as->cand = 0; + ictx->last_gotten_cand = as->cand; + } +} + +static void +cmd_prev_candidate(struct anthy_input_context* ictx) +{ + struct a_segment* as; + + ictx->enum_cand_count++; + + as = ictx->cur_segment; + + if (ictx->enum_reverse) + as->cand = ictx->last_gotten_cand; + else + ictx->enum_reverse = 1; + + if (as->cand == NTH_UNCONVERTED_CANDIDATE) { + while (as) { + if (as->cand == NTH_UNCONVERTED_CANDIDATE) { + as->cand = 0; + } + as = as->next; + } + ictx->last_gotten_cand = 0; + } else { + if (--as->cand < 0) + as->cand = as->ass.nr_candidate - 1; + ictx->last_gotten_cand = as->cand; + } +} + +static void +cmd_move_selection(struct anthy_input_context* ictx, int d) +{ + if (d > 0) + while (d-- > 0 && ictx->cur_segment->next) { + ictx->enum_cand_count = 0; + ictx->cur_segment = ictx->cur_segment->next; + ictx->last_gotten_cand = ictx->cur_segment->cand; + } + else + while (d++ < 0 && ictx->cur_segment->prev) { + ictx->enum_cand_count = 0; + ictx->cur_segment = ictx->cur_segment->prev; + ictx->last_gotten_cand = ictx->cur_segment->cand; + } +} + +static void +cmd_move_to_bol_seg(struct anthy_input_context* ictx) +{ + ictx->cur_segment = ictx->segment; + ictx->enum_cand_count = 0; + ictx->last_gotten_cand = ictx->cur_segment->cand; +} + +static void +cmd_move_to_eol_seg(struct anthy_input_context* ictx) +{ + while (ictx->cur_segment->next) + ictx->cur_segment = ictx->cur_segment->next; + ictx->enum_cand_count = 0; + ictx->last_gotten_cand = ictx->cur_segment->cand; +} + +static void +cmd_unhiragana_candidate(struct anthy_input_context* ictx) +{ + struct a_segment* as; + + for (as = ictx->cur_segment->next; as; as = as->next) + as->cand = 0; +} + +static void +cmd_move_to_bol(struct anthy_input_context* ictx) +{ + terminate_rk(ictx); + + if (ictx->hbuf_follow == NULL) { /* 最適化 */ + ictx->hbuf_follow = ictx->hbuf; + ictx->n_hbuf_follow = ictx->n_hbuf; + ictx->s_hbuf_follow = ictx->s_hbuf; + ictx->hbuf = NULL; + ictx->n_hbuf = 0; + ictx->s_hbuf = 0; + return; + } + + ensure_buffer(&ictx->hbuf_follow, &ictx->s_hbuf_follow, + ictx->n_hbuf + ictx->n_hbuf_follow); + memmove(ictx->hbuf_follow + ictx->n_hbuf, + ictx->hbuf_follow, ictx->n_hbuf_follow); + memcpy(ictx->hbuf_follow, ictx->hbuf, ictx->n_hbuf); + ictx->n_hbuf_follow += ictx->n_hbuf; + ictx->n_hbuf = 0; +} + +static void +cmd_move_to_eol(struct anthy_input_context* ictx) +{ + terminate_rk(ictx); + + if (ictx->hbuf == NULL) { /* 最適化 */ + ictx->hbuf = ictx->hbuf_follow; + ictx->n_hbuf = ictx->n_hbuf_follow; + ictx->s_hbuf = ictx->s_hbuf_follow; + ictx->hbuf_follow = NULL; + ictx->n_hbuf_follow = 0; + ictx->s_hbuf_follow = 0; + return; + } + + ensure_buffer(&ictx->hbuf, &ictx->s_hbuf, + ictx->n_hbuf + ictx->n_hbuf_follow); + memcpy(ictx->hbuf + ictx->n_hbuf, ictx->hbuf_follow, ictx->n_hbuf_follow); + ictx->n_hbuf += ictx->n_hbuf_follow; + ictx->n_hbuf_follow = 0; +} + +static void +cmd_cut(struct anthy_input_context* ictx) +{ + char* tmp_str; + int tmp_int; + + terminate_rk(ictx); + + /* バッファの入れ換えで済ませる */ + tmp_str = ictx->cut; + tmp_int = ictx->s_cut; + ictx->cut = ictx->hbuf_follow; + ictx->n_cut = ictx->n_hbuf_follow; + ictx->s_cut = ictx->s_hbuf_follow; + ictx->hbuf_follow = tmp_str; + ictx->n_hbuf_follow = 0; + ictx->s_hbuf_follow = tmp_int; +} + +/*****************************************************************/ + +/* pure function */ +struct anthy_input_context* +anthy_input_create_context(struct anthy_input_config* cfg) +{ + struct anthy_input_context* ictx; + int i; + + ictx = + (struct anthy_input_context*) malloc(sizeof(struct anthy_input_context)); + ictx->state = ANTHY_INPUT_ST_NONE; + ictx->rkctx = rk_context_create(cfg->break_into_roman); + for (i = 0; i < NR_RKMAP; i++) + rk_register_map(ictx->rkctx, i, cfg->rk_map[i]); + ictx->map_no = RKMAP_HIRAGANA; + rk_select_registered_map(ictx->rkctx, ictx->map_no); + ictx->hbuf = NULL; + ictx->n_hbuf = 0; + ictx->s_hbuf = 0; + ictx->hbuf_follow = NULL; + ictx->n_hbuf_follow = 0; + ictx->s_hbuf_follow = 0; + ictx->enum_cand_limit = DEFAULT_ENUM_CAND_LIMIT; + ictx->enum_cand_count = 0; + ictx->actx = NULL; + ictx->segment = NULL; + ictx->cur_segment = NULL; + ictx->enum_reverse = 0; /* 初期化忘れの修正 */ + ictx->last_gotten_cand = 0; /* 初期化忘れの修正 */ + ictx->commit = NULL; + ictx->n_commit = 0; + ictx->s_commit = 0; + ictx->cut = NULL; + ictx->n_cut = 0; + ictx->s_cut = 0; + ictx->cfg = cfg; + ictx->next_cfg_owner = cfg->owners; + cfg->owners = ictx; + return ictx; +} + +void +anthy_input_free_context(struct anthy_input_context* ictx) +{ + struct anthy_input_context **p; + + reset_anthy_input_context(ictx); + rk_context_free(ictx->rkctx); + + for (p = &ictx->cfg->owners; *p; p = &(*p)->next_cfg_owner) + if (*p == ictx) { + *p = ictx->next_cfg_owner; + break; + } + + free(ictx->hbuf); + free(ictx->hbuf_follow); + free(ictx->commit); + free(ictx->cut); + free(ictx); +} + +void +anthy_input_free_preedit(struct anthy_input_preedit* pedit) +{ + struct anthy_input_segment* p, * q; + + free(pedit->commit); + free(pedit->cut_buf); + for (p = pedit->segment; p; p = q) { + q = p->next; + anthy_input_free_segment(p); + } + free(pedit); +} + +void +anthy_input_free_segment(struct anthy_input_segment* seg) +{ + free(seg->str); + free(seg); +} + +void +anthy_input_str(struct anthy_input_context* ictx, const char* str) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + enter_edit_state(ictx); + cmd_push_key(ictx, str); + if (ictx->map_no == RKMAP_ASCII || + ictx->map_no == RKMAP_WASCII) { + commit_noconv_string(ictx); + leave_edit_state(ictx); + enter_none_state(ictx); + } + break; + case ANTHY_INPUT_ST_EDIT: + cmd_push_key(ictx, str); + break; + case ANTHY_INPUT_ST_CONV: + cmd_commit(ictx); + leave_conv_state(ictx); + enter_edit_state(ictx); + cmd_push_key(ictx, str); + break; + case ANTHY_INPUT_ST_CSEG: + cmd_commit(ictx); + leave_cseg_state(ictx); + enter_conv_state_noinit(ictx); + leave_conv_state(ictx); + enter_edit_state(ictx); + cmd_push_key(ictx, str); + break; + } +} + +void +anthy_input_next_candidate(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + enter_conv_state(ictx); + break; + case ANTHY_INPUT_ST_CONV: + cmd_next_candidate(ictx); + break; + case ANTHY_INPUT_ST_CSEG: + cmd_unhiragana_candidate(ictx); + leave_cseg_state(ictx); + enter_conv_state_noinit(ictx); + cmd_next_candidate(ictx); + break; + } +} + + +void +anthy_input_prev_candidate(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + enter_conv_state(ictx); + break; + case ANTHY_INPUT_ST_CONV: + cmd_prev_candidate(ictx); + break; + case ANTHY_INPUT_ST_CSEG: + leave_cseg_state(ictx); + enter_conv_state_noinit(ictx); + cmd_prev_candidate(ictx); + break; + } +} + +void +anthy_input_quit(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + leave_edit_state(ictx); + enter_none_state(ictx); + break; + case ANTHY_INPUT_ST_CONV: + leave_conv_state(ictx); + enter_edit_state_noinit(ictx); + break; + case ANTHY_INPUT_ST_CSEG: + leave_cseg_state(ictx); + enter_conv_state_noinit(ictx); + leave_conv_state(ictx); + enter_edit_state_noinit(ictx); + break; + } +} + +void +anthy_input_erase_prev(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + cmd_backspace(ictx); + break; + case ANTHY_INPUT_ST_CONV: + leave_conv_state(ictx); + enter_edit_state_noinit(ictx); + break; + case ANTHY_INPUT_ST_CSEG: + leave_cseg_state(ictx); + enter_conv_state_noinit(ictx); + leave_conv_state(ictx); + enter_edit_state_noinit(ictx); + break; + } +} + +void +anthy_input_erase_next(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + cmd_delete(ictx); + break; + case ANTHY_INPUT_ST_CONV: + break; + case ANTHY_INPUT_ST_CSEG: + break; + } +} + +void +anthy_input_commit(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + terminate_rk(ictx); + cmd_commit_unconv(ictx); + leave_edit_state(ictx); + enter_none_state(ictx); + break; + case ANTHY_INPUT_ST_CONV: + cmd_commit(ictx); + leave_conv_state(ictx); + enter_none_state(ictx); + break; + case ANTHY_INPUT_ST_CSEG: + cmd_commit(ictx); + leave_cseg_state(ictx); + enter_conv_state_noinit(ictx); + leave_conv_state(ictx); + enter_none_state(ictx); + break; + } +} + +void +anthy_input_move(struct anthy_input_context* ictx, int lr) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + cmd_move_cursor(ictx, lr); + break; + case ANTHY_INPUT_ST_CONV: + cmd_move_selection(ictx, lr); + break; + case ANTHY_INPUT_ST_CSEG: + cmd_unhiragana_candidate(ictx); + leave_cseg_state(ictx); + enter_conv_state_noinit(ictx); + cmd_move_selection(ictx, lr); + break; + } +} + +void +anthy_input_resize(struct anthy_input_context* ictx, int lr) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + break; + case ANTHY_INPUT_ST_CONV: + enter_cseg_state(ictx); + cmd_resize(ictx, lr); + break; + case ANTHY_INPUT_ST_CSEG: + cmd_resize(ictx, lr); + break; + } +} + +void +anthy_input_beginning_of_line(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + cmd_move_to_bol(ictx); + break; + case ANTHY_INPUT_ST_CONV: + cmd_move_to_bol_seg(ictx); + break; + case ANTHY_INPUT_ST_CSEG: + break; + } +} + +void +anthy_input_end_of_line(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + cmd_move_to_eol(ictx); + break; + case ANTHY_INPUT_ST_CONV: + cmd_move_to_eol_seg(ictx); + break; + case ANTHY_INPUT_ST_CSEG: + break; + } +} + +void +anthy_input_cut(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + cmd_cut(ictx); + break; + case ANTHY_INPUT_ST_CONV: + break; + case ANTHY_INPUT_ST_CSEG: + break; + } +} + +/* key oriented function */ +void +anthy_input_key(struct anthy_input_context* ictx, int c) +{ + char buf[2]; + + buf[0] = (char) c; + buf[1] = '\0'; + anthy_input_str(ictx, buf); +} + +void +anthy_input_space(struct anthy_input_context* ictx) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + enter_edit_state(ictx); + do_cmd_push_key(ictx, " "); + commit_noconv_string(ictx); + leave_edit_state(ictx); + enter_none_state(ictx); + break; + case ANTHY_INPUT_ST_EDIT: + terminate_rk(ictx); + if (rk_selected_map(ictx->rkctx) == RKMAP_SHIFT_ASCII) + do_cmd_push_key(ictx, " "); + else + enter_conv_state(ictx); + break; + case ANTHY_INPUT_ST_CONV: + cmd_next_candidate(ictx); + break; + case ANTHY_INPUT_ST_CSEG: + cmd_unhiragana_candidate(ictx); + leave_cseg_state(ictx); + enter_conv_state_noinit(ictx); + cmd_next_candidate(ictx); + break; + } +} + +/* meta function command */ + +int +anthy_input_get_state(struct anthy_input_context* ictx) +{ + return ictx->state; +} + +static struct anthy_input_segment * +alloc_segment(int flag, int len, int noconv_len) +{ + struct anthy_input_segment *seg; + seg = (struct anthy_input_segment*) + malloc(sizeof(struct anthy_input_segment)); + seg->flag = flag; + seg->cand_no = -1; + seg->nr_cand = -1; + seg->noconv_len = noconv_len; + if (len) { + seg->str = (char *)malloc(len); + } else { + seg->str = NULL; + } + seg->next = NULL; + return seg; +} + +static void +get_edit_mode_preedit(struct anthy_input_context* ictx, + struct anthy_input_preedit* pedit) +{ + struct anthy_input_segment** p; + int len; + /* 左の文字列pending|カーソル|右の文字列 */ + + p = &pedit->segment; + + /* left */ + if (ictx->n_hbuf > 0) { + *p = alloc_segment(ANTHY_INPUT_SF_EDITING, ictx->n_hbuf + 1, + ictx->n_hbuf); + + memcpy((*p)->str, ictx->hbuf, ictx->n_hbuf); + (*p)->str[ictx->n_hbuf] = '\0'; + p = &(*p)->next; + } + + if (ictx->cfg->preedit_mode) { + len = rk_partial_result(ictx->rkctx, NULL, 0); + if (len > 1) { + *p = alloc_segment(ANTHY_INPUT_SF_PENDING, len, len - 1); + + rk_partial_result(ictx->rkctx, (*p)->str, len); + p = &(*p)->next; + } + } else { + len = rk_get_pending_str(ictx->rkctx, NULL, 0); + if (len > 1) { + *p = alloc_segment(ANTHY_INPUT_SF_PENDING, len, len - 1); + + rk_get_pending_str(ictx->rkctx, (*p)->str, len); + p = &(*p)->next; + } + } + + /* cursor */ + *p = alloc_segment(ANTHY_INPUT_SF_CURSOR, 0, 0); + pedit->cur_segment = *p; + p = &(*p)->next; + + /* right */ + if (ictx->n_hbuf_follow > 0) { + *p = alloc_segment(ANTHY_INPUT_SF_EDITING, + ictx->n_hbuf_follow + 1, + ictx->n_hbuf_follow); + memcpy((*p)->str, ictx->hbuf_follow, ictx->n_hbuf_follow); + (*p)->str[ictx->n_hbuf_follow] = '\0'; + } +} + +struct anthy_input_preedit* +anthy_input_get_preedit(struct anthy_input_context* ictx) +{ + struct anthy_input_preedit* pedit; + + pedit = (struct anthy_input_preedit*) + malloc(sizeof(struct anthy_input_preedit)); + + pedit->state = ictx->state; + + /* 未コミットの文字列 */ + if (ictx->n_commit > 0) { + pedit->commit = (char*) malloc(ictx->n_commit + 1); + memcpy(pedit->commit, ictx->commit, ictx->n_commit); + pedit->commit[ictx->n_commit] = '\0'; + ictx->n_commit = 0; + } else { + pedit->commit = NULL; + } + + /* カットバッファの文字列 */ + if(ictx->n_cut > 0) { + pedit->cut_buf = (char*) malloc(ictx->n_cut + 1); + memcpy(pedit->cut_buf, ictx->cut, ictx->n_cut); + pedit->cut_buf[ictx->n_cut] = '\0'; + ictx->n_cut = 0; + } else { + pedit->cut_buf = NULL; + } + + pedit->segment = NULL; + pedit->cur_segment = NULL; + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + case ANTHY_INPUT_ST_NONE: + break; + case ANTHY_INPUT_ST_EDIT: + get_edit_mode_preedit(ictx, pedit); + break; + case ANTHY_INPUT_ST_CONV: + case ANTHY_INPUT_ST_CSEG: + { + struct anthy_input_segment** p; + struct a_segment* as; + + for (as = ictx->segment, p = &pedit->segment; as; as = as->next) { + /* 各文節に対して */ + int len, noconv_len; + + noconv_len = anthy_get_segment(ictx->actx, as->index, + NTH_UNCONVERTED_CANDIDATE, + NULL, 0); + len = anthy_get_segment(ictx->actx, as->index, as->cand, NULL, 0); + *p = alloc_segment(ANTHY_INPUT_SF_NONE, len + 1, noconv_len); + + anthy_get_segment(ictx->actx, as->index, as->cand, (*p)->str, len + 1); + (*p)->cand_no = as->cand; + (*p)->nr_cand = as->ass.nr_candidate; + (*p)->next = NULL; + + if (as == ictx->cur_segment) { + pedit->cur_segment = *p; + (*p)->flag |= ANTHY_INPUT_SF_CURSOR; + if (ictx->enum_cand_count >= ictx->enum_cand_limit) + (*p)->flag |= (ictx->enum_reverse ? + ANTHY_INPUT_SF_ENUM_REVERSE : ANTHY_INPUT_SF_ENUM); + + if (ictx->state == ANTHY_INPUT_ST_CSEG) { + struct a_segment* as1; + + for (as1 = as->next, len = 0; as1; as1 = as1->next) + len += anthy_get_segment(ictx->actx, as1->index, + NTH_UNCONVERTED_CANDIDATE, NULL, 0); + if (len > 0) { + char* s; + + p = &(*p)->next; + *p = alloc_segment(ANTHY_INPUT_SF_FOLLOWING, len + 1, len); + for (as1 = as->next, s = (*p)->str; as1; as1 = as1->next) { + anthy_get_segment(ictx->actx, as1->index, + NTH_UNCONVERTED_CANDIDATE, + s, len - (s - (*p)->str) + 1); + s += anthy_get_segment(ictx->actx, as1->index, + NTH_UNCONVERTED_CANDIDATE, NULL, 0); + } + (*p)->str[len] = '\0'; + (*p)->next = NULL; + } + break; + } + } + + p = &(*p)->next; + } + } + break; + } + + return pedit; +} + +int +anthy_input_map_select(struct anthy_input_context* ictx, int map) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + break; + case ANTHY_INPUT_ST_NONE: + case ANTHY_INPUT_ST_EDIT: + case ANTHY_INPUT_ST_CONV: + case ANTHY_INPUT_ST_CSEG: + return cmdh_map_select(ictx, map); + break; + } + + anthy_input_errno = AIE_INVAL; + return -1; +} + +int +anthy_input_get_selected_map(struct anthy_input_context* ictx) +{ + return ictx->map_no; +} + +struct anthy_input_segment* +anthy_input_get_candidate(struct anthy_input_context* ictx, int cand_no) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_CONV: + return cmdh_get_candidate(ictx, cand_no); + break; + case ANTHY_INPUT_ST_OFF: + case ANTHY_INPUT_ST_NONE: + case ANTHY_INPUT_ST_EDIT: + case ANTHY_INPUT_ST_CSEG: + break; + } + + anthy_input_errno = AIE_INVAL; + return NULL; +} + +int +anthy_input_select_candidate(struct anthy_input_context* ictx, int cand) +{ + switch (ictx->state) { + case ANTHY_INPUT_ST_OFF: + case ANTHY_INPUT_ST_NONE: + case ANTHY_INPUT_ST_EDIT: + break; + case ANTHY_INPUT_ST_CONV: + return cmdh_select_candidate(ictx, cand); + break; + case ANTHY_INPUT_ST_CSEG: + break; + } + + anthy_input_errno = AIE_INVAL; + return -1; +} + +int +anthy_input_edit_toggle_config(struct anthy_input_config *cfg, char tg) +{ + return anthy_input_do_edit_toggle_option(cfg->rk_option, tg); +} + +int +anthy_input_edit_rk_config(struct anthy_input_config *cfg, int map, + const char *from, const char *to, const char *follow) +{ + return + anthy_input_do_edit_rk_option(cfg->rk_option, map, + from, to, follow); +} + +int +anthy_input_clear_rk_config(struct anthy_input_config *cfg, + int use_default) +{ + return + anthy_input_do_clear_rk_option(cfg->rk_option, use_default); +} + +int +anthy_input_break_into_roman_config(struct anthy_input_config *cfg, + int brk) +{ + int old_val; + old_val = cfg->break_into_roman; + cfg->break_into_roman = brk; + return old_val; +} + +int +anthy_input_preedit_mode_config(struct anthy_input_config *cfg, + int val) +{ + int old_val; + old_val = cfg->preedit_mode; + cfg->preedit_mode = val; + return old_val; +} + +void +anthy_input_change_config(struct anthy_input_config* cfg) +{ + struct anthy_input_context* p; + + struct rk_map* h_map = cfg->rk_map[RKMAP_HIRAGANA]; + struct rk_map* k_map = cfg->rk_map[RKMAP_KATAKANA]; + struct rk_map* s_map = cfg->rk_map[RKMAP_SHIFT_ASCII]; + struct rk_map* hk_map = cfg->rk_map[RKMAP_HANKAKU_KANA]; + + cfg->rk_map[RKMAP_HIRAGANA] = make_rkmap_hiragana(cfg->rk_option); + cfg->rk_map[RKMAP_KATAKANA] = make_rkmap_katakana(cfg->rk_option); + cfg->rk_map[RKMAP_SHIFT_ASCII] = make_rkmap_shiftascii(cfg->rk_option); + cfg->rk_map[RKMAP_HANKAKU_KANA] = make_rkmap_hankaku_kana(cfg->rk_option); + + /* このconfigを共有するコンテキストすべてに対して */ + for (p = cfg->owners; p; p = p->next_cfg_owner) { + reset_anthy_input_context(p); + rk_register_map(p->rkctx, RKMAP_HIRAGANA, cfg->rk_map[RKMAP_HIRAGANA]); + rk_register_map(p->rkctx, RKMAP_KATAKANA, cfg->rk_map[RKMAP_KATAKANA]); + rk_register_map(p->rkctx, RKMAP_SHIFT_ASCII, + cfg->rk_map[RKMAP_SHIFT_ASCII]); + rk_register_map(p->rkctx, RKMAP_HANKAKU_KANA, + cfg->rk_map[RKMAP_HANKAKU_KANA]); + rk_select_registered_map(p->rkctx, RKMAP_HIRAGANA); + } + + rk_map_free(h_map); + rk_map_free(k_map); + rk_map_free(s_map); + rk_map_free(hk_map); +} + +struct anthy_input_config* +anthy_input_create_config(void) +{ + struct anthy_input_config* cfg; + + cfg = (struct anthy_input_config*) malloc(sizeof(struct anthy_input_config)); + + cfg->rk_option = anthy_input_create_rk_option(); + cfg->break_into_roman = 0; + cfg->preedit_mode = 0; + cfg->rk_map[RKMAP_ASCII] = make_rkmap_ascii(cfg->rk_option); + cfg->rk_map[RKMAP_SHIFT_ASCII] = make_rkmap_shiftascii(cfg->rk_option); + cfg->rk_map[RKMAP_HIRAGANA] = make_rkmap_hiragana(cfg->rk_option); + cfg->rk_map[RKMAP_KATAKANA] = make_rkmap_katakana(cfg->rk_option); + cfg->rk_map[RKMAP_WASCII] = make_rkmap_wascii(cfg->rk_option); + cfg->rk_map[RKMAP_HANKAKU_KANA] = make_rkmap_hankaku_kana(cfg->rk_option); + cfg->owners = NULL; + + return cfg; +} + +void +anthy_input_free_config(struct anthy_input_config* cfg) +{ + int err; + + /* このconfigを共有する全てのcontextを事前に解放する事 */ + assert(!cfg->owners); + + rk_map_free(cfg->rk_map[RKMAP_ASCII]); + rk_map_free(cfg->rk_map[RKMAP_SHIFT_ASCII]); + rk_map_free(cfg->rk_map[RKMAP_HIRAGANA]); + rk_map_free(cfg->rk_map[RKMAP_KATAKANA]); + rk_map_free(cfg->rk_map[RKMAP_WASCII]); + rk_map_free(cfg->rk_map[RKMAP_HANKAKU_KANA]); + + err = anthy_input_free_rk_option(cfg->rk_option); + free(cfg); +} + +int +anthy_input_init(void) +{ + return anthy_init(); +} + +void +anthy_input_set_personality(const char *personality) +{ + anthy_set_personality(personality); +} + +anthy_context_t +anthy_input_get_anthy_context(struct anthy_input_context *ictx) +{ + return ictx->actx; +} |