Newer
Older
scim-wnn / scim-wnn / src / romkan.cpp
/***************************************************************************
 *   Copyright (C) 2004 by TAM(Teppei Tamra)                               *
 *   tam-t@par.odn.ne.jp                                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "romkan.h"
#include "romkan_table.h"

#ifdef HAVE_CONFIG_H
  #include <config.h>
#endif

// 国際化のおまじない。
#ifdef HAVE_GETTEXT
  #include <libintl.h>
  #define _(String) dgettext(GETTEXT_PACKAGE,String)
  #define N_(String) (String)
#else
  #define _(String) (String)
  #define N_(String) (String)
  #define bindtextdomain(Package,Directory)
  #define textdomain(domain)
  #define bind_textdomain_codeset(domain,codeset)
#endif

Romkan::Romkan(ConfigPointer cfg) : PreEditor(cfg)
{
    reset();
    iconvert.set_encoding ("EUC-JP");
    mode = ROMA;

    // ここでやるべきことでは無いが。
    nnMode = cfg->read(String("/IMEngine/Wnn/Romkan/nnMode"),false);

    unsigned int i = 0;
    while(strcmp(_RomkanTable[i],"") != 0) {
        RomkanTableEntry e;
        e.key = String(_RomkanTable[i]);
        WideString w;
        iconvert.convert(w,String(_RomkanTable[i + 1]));
        e.kana = w;
        RomkanTable.push_back(e);
        i += 2;
    }

}


Romkan::~Romkan()
{
}



/*!
    \fn Romkan::setPos(int p)
 */
void Romkan::setPos(int p)
{
    if (p < 0) p = 0;
    else if (p > getTextLength()) p = getTextLength();
    pos = p;
    buf.clear();
}


/*!
    \fn Romkan::clear()
 */
void Romkan::clear()
{
    text.clear();
    buf.clear();
}


/*!
    \fn Romkan::insert(char k)
 */
WideString Romkan::insert(char k)
{
    String s;
    s = k;
    if (k == 0) return(text);
    switch(mode) {
        case ASCII: {
            buf.clear();
            text = text.substr(0,pos) + utf8_mbstowcs(s) + text.substr(pos);
            pos ++;
            return(text);
            break;
        }
        case WASCII: {
            buf.clear();
            WideString w = utf8_mbstowcs(s);
            convHanZen(w);
            text = text.substr(0,pos) + w + text.substr(pos);
            pos ++;
            return(text);
            break;
        }
        case ROMA: {
            if (k == 'q') {
                mode = ASCII;
                buf.clear();
                return(text);
            } else if (k == 'Q') {
                mode = WASCII;
                buf.clear();
                return(text);
            }
            buf += s;
            text = text.substr(0,pos) + utf8_mbstowcs(s) + text.substr(pos);
            pos ++;
            return(eval());
            break;
        }
    }
    return(text);
}


/*!
    \fn Romkan::eval()
 */
WideString Romkan::eval()
{
    // エヴァる。

    if (buf.length() == 2) {

        // n+母音以外は「ん」+子音である
        // ただし、nyは除外である。
        if (buf[0] == 'n') {
            String b = "aiueoy";
            if (nnMode) b += "n";
            bool boin = false;
            for(unsigned int i = 0;i < b.length();i ++) {
                if (buf[1] == b[i]) boin = true;
            }
            if (!boin) {
                text = text.substr(0,pos - 2) + convChars[KANA_N] + text.substr(pos - 1);
                buf = buf.substr(buf.length() - 1,1);
            }
        }

        // 同じ文字が2文字続くとそれは「っ」+子音である。母音の連打がbufに残ってはいないはず。
        else if (buf[0] == buf[1]) {
            text = text.substr(0,pos - 2) + convChars[KANA_XTU] + text.substr(pos - 1);
            buf = buf.substr(buf.length() - 1,1);
            return(text);
        }
    }

    // テーブルを検索して入力する。
    for(unsigned int i = 0;i < RomkanTable.size();i ++) {
        if (buf == RomkanTable[i].key) {
            if (!RomkanTable[i].kana.size()) {
                return(text); // 保留する。
            }
            text = text.substr(0,pos - buf.length()) + RomkanTable[i].kana + text.substr(pos);
            pos = pos - buf.length() + RomkanTable[i].kana.length();
            buf.clear();
            return(text);
        }
    }
    if (buf.length()) {
        buf = buf.substr(1);
        return(eval());
    }

    return(text);
}




/*!
    \fn Romkan::reset()
 */
void Romkan::reset()
{
    clear();
    pos = 0;
    mode = ROMA;
}

/*!
    \fn PreEditor::setText(const WideString &t)
 */
void Romkan::setText(const WideString &t)
{
    text = t;
    buf.clear();
}


/*!
    \fn Romkan::getText(bool hosei)
 */
WideString Romkan::getText(bool hosei)
{
    if (hosei) {
        if (buf.length()) {
            if (buf.substr(buf.length() - 1,1) == "n") {
                text = text.substr(0,pos - 1) + convChars[KANA_N];
            }
        }
    }
    return(text);
}


/*!
    \fn Romkan::backspace()
 */
void Romkan::backspace()
{
    if (getPos() == 0) return;
    text = text.substr(0,pos - 1) + text.substr(pos);
    setPos(pos - 1);
    // BSは小バッファもBSするゾ。
    if (buf.length()) buf = buf.substr(0,buf.length() - 1);
}



/*!
    \fn Romkan::del()
 */
void Romkan::del()
{
    if (getPos() == getTextLength()) return;
    text = text.substr(0,pos) + text.substr(pos + 1);
}



/*!
    \fn Romkan::hiraKata()
 */
void Romkan::hiraKata()
{
    convHiraKata(text);
}


/*!
    \fn Romkan::kataHira()
 */
void Romkan::kataHira()
{
    convKataHira(text);
}


/*!
    \fn Romkan::keyEventHook(const KeyEvent &key)
 */
bool Romkan::keyEventHook(const KeyEvent &key)
{
    if ((isprint(key.code)) && ((mode == ASCII) || (mode == WASCII))) {
        if ((!key.is_alt_down()) && (!key.is_control_down())) {
            insert(key.get_ascii_code());
            return(true);
        }
    }

    if (!buf.length()) return(false);
    if (buf[buf.length() - 1] == 'Z') {
        if (key.code == SCIM_KEY_space) {
            insert(' ');
            return(true);
        }
    }
    return(false);
}


/*!
    \fn Romkan::getModeName()
 */
String Romkan::getModeName()
{
    switch(mode) {
        case ROMA: {
            return(String(_("Roma-Kana")));
            break;
        }
        case ASCII: {
            return(String(_("Ascii")));
            break;
        }
        case WASCII: {
            return(String(_("Wide Ascii")));
            break;
        }
    }
}


/*!
    \fn Romkan::cancelEvent()
 */
bool Romkan::cancelEvent()
{
    if ((mode == ASCII) || (mode == WASCII)) {
        mode = ROMA;
        return(true);
    }
    return(false);
}


/*!
    \fn Romkan::inputEvent(const KeyEvent &key)
 */
bool Romkan::inputEvent(const KeyEvent &key)
{
    // 喰っておくべきもの。
    if ((key.code == SCIM_KEY_Shift_L) ||
        (key.code == SCIM_KEY_Shift_R) ||
        (key.code == SCIM_KEY_Control_L) ||
        (key.code == SCIM_KEY_Control_R) ||
        (key.code == SCIM_KEY_Alt_L) ||
        (key.code == SCIM_KEY_Alt_R) ||
        (key.code == SCIM_KEY_Super_L) ||
        (key.code == SCIM_KEY_Super_R) ||
        (key.code == SCIM_KEY_Hyper_L) ||
        (key.code == SCIM_KEY_Hyper_R)) return(true);
    if (key.get_ascii_code() && (!key.is_alt_down()) && (!key.is_control_down())) {
        if (key.get_ascii_code() == ' ') return(false);
        // 素直に返すべきもの
        if ((key.code == SCIM_KEY_Return) ||
            (key.code == SCIM_KEY_Linefeed) ||
            (key.code == SCIM_KEY_Tab)) return(false);
        insert(key.get_ascii_code());
        return(true);
    }
    return(false);
}


/*!
    \fn Romkan::getName()
 */
String Romkan::getName()
{
    return(String(_("Roma")));
}