/* * 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 #include #include #include #include #include #include #include #include #include #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; }