// Anthy 用のplugin
//
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#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:
*/
syntax highlighted by Code2HTML, v. 0.9.1