// Anthy 用のplugin // #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include "anthy.xpm" #include "jmode.h" #include "anthyconv.h" //input mode #define INPUT_MODE_RAW 0 #define INPUT_MODE_HIRA 1 #define INPUT_MODE_KATA 2 #define INPUT_MODE_WIDE 3 static atom_t A_extend_segment, A_shorten_segment; static atom_t A_anthy_personality; static struct anthy_input_config *config; static void init_key_atom() { A_extend_segment = get_atom_by_name("anthy_extend_segment"); A_shorten_segment = get_atom_by_name("anthy_shorten_segment"); A_anthy_personality = get_atom_by_name("AnthyPersonality"); bind_str_to_atom("C-o", A_extend_segment); bind_str_to_atom("S-Right", A_extend_segment); bind_str_to_atom("S-Left", A_shorten_segment); bind_str_to_atom("C-i", A_shorten_segment); } static void decode_arg(char *dst, char *src) { int c = src[0]; if (c == '\\') { int d = src[1]; src++;src++; switch (d) { case '\\': *dst = '\\'; dst++; break; case 'x': case 'X': { char buf[10]; int num; strcpy(buf, src); sscanf(buf, "%x", &num); unsigned char buf2[5]; buf2[0] = (num>>8) & 255; buf2[1] = num & 255; buf2[2] = 0; sprintf(dst, "%s", (char *)buf2); return ; } break; } } else { *dst = c; if (!c) { return ; } dst ++; src ++; } decode_arg(dst, src); } static void do_edit_rk_config(int m, char *from, char *to, char *follow) { char buf[10]; decode_arg(buf, to); anthy_input_edit_rk_config(config, m, from, buf, follow); } static void anthy_conf_hook(char *str) { if (!config) { config = anthy_input_create_config(); anthy_input_clear_rk_config(config, 0); } if (strlen(str) > 20) { return ; } char buf1[20], buf2[20], buf3[20], buf4[20]; int c, m; c = sscanf(str, "%s %s %s %s", buf1, buf2, buf3, buf4); if (c < 3) { return ; } if (buf1[0] == 'h') { m = 2; } else { m = 3; } if (c == 3) { do_edit_rk_config(m, buf2, buf3, 0); } else { do_edit_rk_config(m, buf2, buf3, buf4); } anthy_input_change_config(config); } void init_preconf_kkconv() { add_conf_hook("anthy", anthy_conf_hook); } bool init_conv() { // もし初期化で失敗したら、この関数はfalseを返す。 AnthyConv *anthy = new AnthyConv(); init_key_atom(); if (anthy_input_init()) { delete anthy; return false; } if (atom_t a = get_bound_atoms(A_anthy_personality, 0)) { anthy_input_set_personality(get_atom_name(a)); } register_kkconv(anthy); if (!config) { config = anthy_input_create_config(); } return true; } AnthyConv::~AnthyConv() { // 終了の処理 } KKContext *AnthyConv::createContext(XimIC *ic) { // 入力コンテキストを作る。 AnthyContext *anthy; anthy = new AnthyContext(this, ic); return anthy; } char **AnthyConv::getIcon() { // toolbarに出てくるアイコンを返す。 return anthy_xpm; } void AnthyConv::onPushIcon() { // toolbarの押された時に呼ばれる。 } char *AnthyConv::getModeName(int num) { switch (num) { case INPUT_MODE_RAW: return "a"; case INPUT_MODE_HIRA: return "あ"; case INPUT_MODE_KATA: return "ア"; case INPUT_MODE_WIDE: return "A"; } return NULL; } ///////////////////////////////////// // AnthyContext::AnthyContext(AnthyConv *, XimIC *ic) : KKContext(ic) { mAic = anthy_input_create_context(config); mIsOn = false; mPedit = NULL; mCands = NULL; } AnthyContext::~AnthyContext() { // 使わなくなったコンテクストを解放 anthy_input_free_context(mAic); if (mCands) { delete mCands; } } int AnthyContext::getMode() { if (mIsOn) { switch (anthy_input_get_selected_map(mAic)) { case ANTHY_INPUT_MAP_HIRAGANA: return INPUT_MODE_HIRA; case ANTHY_INPUT_MAP_KATAKANA: return INPUT_MODE_KATA; } } return INPUT_MODE_RAW; } void AnthyContext::OnUpdatePe(pe_stat *pe) { // preeditが更新される時に呼ばれる。 pe->clear(); if (!mIsOn) { return ; } struct anthy_input_segment *seg; for (seg = mPedit->segment; seg; seg = seg->next) { char *str = "^"; if (seg->str) { str = seg->str; } if (seg->flag & ANTHY_INPUT_SF_CURSOR) { pe->new_segment(PE_REVERSE); } else { pe->new_segment(PE_UNDERLINE); } jstring_t js; str_to_jstring(&js, str); jstring_t::iterator it; for (it = js.begin(); it != js.end(); it++) { pe->push_cchar(*it); } } pe->cands = mCands; } int AnthyContext::procRawMode(keyState *e) { if (e->is_bind_to(A_hira_mode)) { mIsOn = true; return UPDATE_MODE; } return COMMIT_RAW; } void AnthyContext::updateCandidates() { struct anthy_input_segment *seg; struct anthy_input_segment *cseg = NULL; if (mCands) { delete mCands; mCands = NULL; } for (seg = mPedit->segment; seg; seg = seg->next) { if (seg->flag & (ANTHY_INPUT_SF_ENUM | ANTHY_INPUT_SF_ENUM_REVERSE)) { cseg = seg; } } if (!cseg) { return ; } mCands = new Candidates; mCands->nth = cseg->cand_no; int i; for (i = 0; i < cseg->nr_cand; i++) { seg = anthy_input_get_candidate(mAic, i); jstring_t js; str_to_jstring(&js, seg->str); mCands->cands.push_back(js); anthy_input_free_segment(seg); } seg = anthy_input_get_candidate(mAic, mCands->nth); anthy_input_free_segment(seg); } int AnthyContext::procCommandKey(keyState *e) { bool pe = true; if (!mPedit || !mPedit->segment) { pe = false; } if (e->is_bind_to(A_latin_mode) && !pe) { mIsOn = false; return UPDATE_MODE; } if (!pe && e->char_code() == 0) { return COMMIT_RAW; } if (e->is_bind_to(A_commit) || e->is_bind_to(A_return)) { anthy_input_commit(mAic); return DO_NOTHING; } if (e->is_bind_to(A_do_conv)) { anthy_input_space(mAic); return DO_NOTHING; } if (e->is_bind_to(A_cancel) || (e->is_bind_to(A_delete_back) && ((anthy_input_get_state(mAic) == ANTHY_INPUT_ST_CONV) || (anthy_input_get_state(mAic) == ANTHY_INPUT_ST_CSEG)))) { anthy_input_quit(mAic); return DO_NOTHING; } if (e->is_bind_to(A_go_line_head)) { anthy_input_beginning_of_line(mAic); return DO_NOTHING; } if (e->is_bind_to(A_go_line_end)) { anthy_input_end_of_line(mAic); return DO_NOTHING; } if (e->is_bind_to(A_go_right)) { anthy_input_move(mAic, 1); return DO_NOTHING; } if (e->is_bind_to(A_go_left)) { anthy_input_move(mAic, -1); return DO_NOTHING; } if (e->is_bind_to(A_delete_here)) { anthy_input_erase_next(mAic); return DO_NOTHING; } if (e->is_bind_to(A_delete_back)) { anthy_input_erase_prev(mAic); return DO_NOTHING; } if (e->is_bind_to(A_extend_segment)) { anthy_input_resize(mAic, 1); return DO_NOTHING; } if (e->is_bind_to(A_shorten_segment)) { anthy_input_resize(mAic, -1); return DO_NOTHING; } if (e->is_bind_to(A_next_candidate)) { anthy_input_next_candidate(mAic); return DO_NOTHING; } if (e->is_bind_to(A_prev_candidate)) { anthy_input_prev_candidate(mAic); return DO_NOTHING; } return ANTHY_PROC_MASK; } int AnthyContext::procInputMode(keyState *e) { int res; res = procCommandKey(e); if (res & ANTHY_PROC_MASK) { int cc; cc = e->char_code(); if (cc) { anthy_input_key(mAic, cc); } res = DO_NOTHING; } updateAnthyPreedit(); if (mPedit->commit) { jstring_t js; str_to_jstring(&js, mPedit->commit); commit_jstring(&js); } update_preedit(); return res & KK_PUSHKEY_MASK; } void AnthyContext::updateAnthyPreedit() { if (mPedit) { anthy_input_free_preedit(mPedit); mPedit = NULL; } mPedit = anthy_input_get_preedit(mAic); updateCandidates(); } int AnthyContext::pushKey(keyState *e) { if (e->is_modifier()) { return DO_NOTHING; } if (!mIsOn) { return procRawMode(e); } return procInputMode(e); } void AnthyContext::setMode(int m) { if (mIsOn) { anthy_input_quit(mAic); } mIsOn = true; switch (m) { case 0: mIsOn = false; break; case 1: anthy_input_map_select(mAic, ANTHY_INPUT_MAP_HIRAGANA); break; case 2: anthy_input_map_select(mAic, ANTHY_INPUT_MAP_KATAKANA); break; case 3: anthy_input_map_select(mAic, ANTHY_INPUT_MAP_WALPHABET); break; } } jstring_t *AnthyContext::clear() { // コンテキストを初期化 return 0; } /* * Local variables: * c-indent-level: 4 * c-basic-offset: 4 * End: */