Newer
Older
scim-wnn / scim-wnn / src / scim_wnn_imengine.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.             *
 ***************************************************************************/

// って言うか先にWnnをC++向けに優しく包み込む母のようなライブラリ激しく希望。
// ああそうですね、「お前がやれ」ですよね。

#define Uses_SCIM_UTILITY
#define Uses_SCIM_IMENGINE
#define Uses_SCIM_LOOKUP_TABLE
#define Uses_SCIM_CONFIG_BASE
#define Uses_SCIM_ICONV

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

// 国際化のおまじない。
// まぁ愚痴を言わせてもらえば、これを毎回どうにかしなきゃいけないっつーのは
// どうなんでしょうなぁ…。
// KDEなら飛ばせる部分ですが何か?。
#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

// scimのおまじない。
// 一言で言えば、めんどくs
#include "scim_wnn_imengine.h"
#include "scim_wnn_def.h"

#define scim_module_init wnn_LTX_scim_module_init
#define scim_module_exit wnn_LTX_scim_module_exit
#define scim_imengine_module_init wnn_LTX_scim_imengine_module_init
#define scim_imengine_module_create_factory wnn_LTX_scim_imengine_module_create_factory
#ifndef SCIM_WNN_ICON_FILE
  #define SCIM_WNN_ICON_FILE           (SCIM_ICONDIR "/scim-wnn.png")
#endif

#define SCIM_PROP_WNN_INPUTMODE "/IMEngine/Wnn/InputMode"

static Pointer <WnnFactory> _scim_wnn_factory;
static ConfigPointer _scim_config;

extern "C" {
    // あれでしょう。
    // KDEなんかでも使われてる動的ローディングの小技。
    // Cリンケージで関数名固定させて、そっからインスタンス作るっつーあれ。
    // 面倒だよねぇ。まぁ別に良いけどさ。
    void scim_module_init (void)
    {
    }

    void scim_module_exit (void)
    {
        _scim_wnn_factory.reset ();
        _scim_config.reset ();
    }

    unsigned int scim_imengine_module_init (const ConfigPointer &config)
    {
        _scim_config = config;
        return 1;
    }

    IMEngineFactoryPointer scim_imengine_module_create_factory (unsigned int factory)
    {
        if (factory != 0) return NULL;
        if (_scim_wnn_factory.null ()) {
            _scim_wnn_factory =
                new WnnFactory (utf8_mbstowcs (String (_("Wnn"))),String("ja_JP"));
        }
        return _scim_wnn_factory;
    }
}

WnnFactory::WnnFactory() {
    m_name = utf8_mbstowcs(_("Wnn"));
    set_languages(String("ja_JP"));
}

WnnFactory::~ WnnFactory() {
}

WnnFactory::WnnFactory(const WideString & name, const String & languages) {
    // 文字数制限か。
    if (name.length () <= 8)
        m_name = name;
    else
        m_name.assign (name.begin (), name.begin () + 8);
    // とりあえず日本語環境で固定したいトコだ。
    if (languages == String ("default"))
        set_languages (String (_("ja_JP")));
    else
        set_languages (languages);
}

WideString WnnFactory::get_name () const
{
    // 名前を返すのね。utf8_mbstowcs(_("Wnn"))で。
    return m_name;
}

WideString WnnFactory::get_authors () const
{
    // AUTHERね。
    return utf8_mbstowcs (String (_("(C) 2004 TAM(Teppei Tamra) <tam-t@par.odn.ne.jp>")));
}

WideString WnnFactory::get_credits () const
{
    // CREDITね。とりあえず空で。
    return WideString ();
}

WideString WnnFactory::get_help () const
{
    // HELPも書かないとダメなのね。
    return utf8_mbstowcs (String (_("SCIM-WNN HELP")));
}

String WnnFactory::get_uuid () const
{
    // uuidgen叩いて識別と。ユニークならなんでもよさげだけども。
    return String ("c069395a-d62f-4a77-8229-446e44a99976");
}

String WnnFactory::get_icon_file () const
{
    // アイコンを指定。作らないとね。
    return String (SCIM_WNN_ICON_FILE);
}

IMEngineInstancePointer WnnFactory::create_instance (const String& encoding, int id)
{
    // 実際にインスタンスを作る。
    return new WnnInstance (this, encoding, id);
}



// キーイベントチェック

void WnnKeyEventList::append(const KeyEvent &k) {
    push_back(k);
}

void WnnKeyEventList::append(int code,int mask) {
    KeyEvent k;
    k.code = code;
    k.mask = mask;
    append(k);
}

bool WnnKeyEventList::comp(const KeyEvent &k) {
    for (unsigned int i = 0;i < size();i ++) {
        if ((at(i).code == k.code) && (at(i).mask == k.mask)) {
            return(true);
        }
    }
    return(false);
}


// 淫 醋 箪 笥
// 現物。


WnnInstance::WnnInstance (WnnFactory *factory, const String& encoding, int id)
    : IMEngineInstanceBase (factory, encoding, id)
{
    m_conversion = false;
    m_lookup = false;
    m_connected = false;
    host = _scim_config->read(String(SCIM_CONFIG_WNN_SERVER),String("localhost"));
    rc = _scim_config->read(String(SCIM_CONFIG_WNN_RC),String("/usr/lib/wnn7/ja_JP/wnnenvrc"));
    alp = _scim_config->read(String(SCIM_CONFIG_WNN_ALP),SCIM_DEFAULT_WNN_ALP);


    // デフォルトキー設定。
    // 設定ファイルから読むようにしてごにょごにょ。
    scim_string_to_key_list(k_conversion_start,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_START),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_START)));
    scim_string_to_key_list(k_cancel,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CANCEL),
            String(SCIM_DEFAULT_WNN_KEY_CANCEL)));
    scim_string_to_key_list(k_delete,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_DELETE),
            String(SCIM_DEFAULT_WNN_KEY_DELETE)));
    scim_string_to_key_list(k_backspace,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_BACKSPACE),
            String(SCIM_DEFAULT_WNN_KEY_BACKSPACE)));
    scim_string_to_key_list(k_commit,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_COMMIT),
            String(SCIM_DEFAULT_WNN_KEY_COMMIT)));
    scim_string_to_key_list(k_conversion_next,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_NEXT),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_NEXT)));
    scim_string_to_key_list(k_conversion_prev,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_PREV),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_PREV)));
    scim_string_to_key_list(k_conversion_expand,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_EXPAND),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_EXPAND)));
    scim_string_to_key_list(k_conversion_shrink,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_SHRINK),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_SHRINK)));
    scim_string_to_key_list(k_conversion_forward,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_FORWARD),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_FORWARD)));
    scim_string_to_key_list(k_conversion_backward,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_BACKWARD),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_BACKWARD)));
    scim_string_to_key_list(k_forward,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_FORWARD),
            String(SCIM_DEFAULT_WNN_KEY_FORWARD)));
    scim_string_to_key_list(k_backward,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_BACKWARD),
            String(SCIM_DEFAULT_WNN_KEY_BACKWARD)));
    scim_string_to_key_list(k_lookup_popup,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_LOOKUPPOPUP),
            String(SCIM_DEFAULT_WNN_KEY_LOOKUPPOPUP)));
    scim_string_to_key_list(k_lookup_pageup,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_LOOKUPPAGEUP),
            String(SCIM_DEFAULT_WNN_KEY_LOOKUPPAGEUP)));
    scim_string_to_key_list(k_lookup_pagedown,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_LOOKUPPAGEDOWN),
            String(SCIM_DEFAULT_WNN_KEY_LOOKUPPAGEDOWN)));

}

WnnInstance::~ WnnInstance()
{
}

bool WnnInstance::process_key_event (const KeyEvent& key)
{
    if (key.is_key_release()) return false;
    if (m_conversion) return(process_conversion_key_event(key));
    else return(process_preedit_key_event(key));
}


/*!
    \fn WnnInstance::process_preedit_key_event(const KeyEvent &key)
 */
bool WnnInstance::process_preedit_key_event(const KeyEvent &key)
{
    if (k_conversion_start.comp(key)) {
        if (!m_rk.getTextLength()) {
            return(false);
        }
        startConversion(m_rk.getText(true));
        show_preedit_string();
        if (m_conversion) {
            update_preedit_string(wnn.getText(),wnn.getAttributeList());
            update_preedit_caret(wnn.getCaretPos());
        }
        return(true);
    } else
    if (k_commit.comp(key)) {
        if (!m_rk.getTextLength()) {
            return(false);
        }
        commit_string(m_rk.getText(true));
        m_rk.reset();
        hide_preedit_string();
        return(true);
    } else
    if (k_forward.comp(key) || k_backward.comp(key)) {
        if (!m_rk.getTextLength()) {
            return(false);
        }
        k_backward.comp(key) ? m_rk.setPos(m_rk.getPos() - 1) : m_rk.setPos(m_rk.getPos() + 1);
        update_preedit_caret(m_rk.getPos());
        return(true);
    } else
    if (k_backspace.comp(key)) {
        if (!m_rk.getTextLength()) {
            return(false);
        }
        m_rk.backspace();
        update_preedit_string(m_rk.getText());
        update_preedit_caret(m_rk.getPos());
        return(true);
    } else
    if (k_delete.comp(key)) {
        if (!m_rk.getTextLength()) {
            return(false);
        }
        m_rk.del();
        update_preedit_string(m_rk.getText());
        update_preedit_caret(m_rk.getPos());
        return(true);
    } else
    if (k_cancel.comp(key)) {
        if (!m_rk.getTextLength()) {
            return(false);
        }
        m_rk.reset();
        hide_preedit_string();
        return(true);
    } else
    if (isprint(key.code)) {
        if (key.mask & (SCIM_KEY_AltMask | SCIM_KEY_ControlMask)) return(false);
        show_preedit_string();
        SCIM_DEBUG_IMENGINE(1) << key.get_key_string() << "\n";
        update_preedit_string(m_rk.insert(key.get_ascii_code()));
        update_preedit_caret(m_rk.getPos());
        return true;
    }
    return false;
}

/*!
    \fn WnnInstance::process_conversion_key_event(const KeyEvent &key)
 */
bool WnnInstance::process_conversion_key_event(const KeyEvent &key)
{
    if ((alp < alp_count) && (alp != 0)) {
        if (!m_lookup) startLookup();
    }

    if (k_lookup_popup.comp(key)) {
        if (m_lookup) return(true);
        startLookup();
        return(true);
    } else
    if (k_lookup_pageup.comp(key)) {
        if (m_lookup) {
            lookup_table_page_up();
        }
    } else
    if (k_lookup_pagedown.comp(key)) {
        if (m_lookup) {
            lookup_table_page_down();
        }
    } else
    if (k_commit.comp(key)) {
        commit_string(wnn.getText());
        wnn.updateFrequency();
        m_rk.reset();
        wnn.reset();
        m_conversion = false;
        hide_preedit_string();
        hide_lookup_table();
        hide_aux_string();
        m_lookup = false;
        alp_count = 0;
        return(true);
    } else
    if (k_cancel.comp(key) || k_backspace.comp(key)) {
        wnn.reset();
        m_conversion = false;
        update_preedit_string(m_rk.getText());
        update_preedit_caret(m_rk.getPos());
        hide_lookup_table();
        hide_aux_string();
        m_lookup = false;
        alp_count = 0;
        return(true);
    } else
    if (k_conversion_next.comp(key) || k_conversion_prev.comp(key)) {
        k_conversion_prev.comp(key) ? m_convList.pos --: m_convList.pos ++;
        if (m_convList.pos >= m_convList.count) m_convList.pos = 0;
        else if (m_convList.pos < 0) m_convList.pos = m_convList.count - 1;
        alp_count ++;

        wnn.select(m_convList.pos);
        update_preedit_string(wnn.getText(),wnn.getAttributeList());
        update_preedit_caret(wnn.getCaretPos());
        if (m_lookup) {
            m_lookup_table.set_cursor_pos(m_convList.pos);
            update_lookup_table(m_lookup_table);
        }
        return(true);
    } else
    if (k_conversion_expand.comp(key) || k_conversion_shrink.comp(key)) {
        bool r;
        k_conversion_shrink.comp(key) ? r = wnn.resizeRegion(-1) : r = wnn.resizeRegion(1);
        if (!r) return(true);
        m_convList = wnn.getConversionList();
        update_preedit_string(wnn.getText(),wnn.getAttributeList());
        update_preedit_caret(wnn.getCaretPos());
        hide_lookup_table();
        hide_aux_string();
        m_lookup = false;
        alp_count = 0;
        return(true);
    } else
    if (k_conversion_forward.comp(key) || k_conversion_backward.comp(key)) {
        k_conversion_backward.comp(key) ? wnn.setPos(wnn.getPos() - 1) : wnn.setPos(wnn.getPos() + 1);
        m_convList = wnn.getConversionList();
        update_preedit_string(wnn.getText(),wnn.getAttributeList());
        update_preedit_caret(wnn.getCaretPos());
        hide_lookup_table();
        hide_aux_string();
        m_lookup = false;
        alp_count = 0;
        return(true);
    } else
    if (isprint(key.code)) {
        if (key.mask & (SCIM_KEY_AltMask | SCIM_KEY_ControlMask)) return(false);
        commit_string(wnn.getText());
        wnn.updateFrequency();
        m_rk.reset();
        wnn.reset();
        m_conversion = false;
        hide_preedit_string();
        hide_lookup_table();
        hide_aux_string();
        m_lookup = false;
        alp_count = 0;
        return(process_preedit_key_event(key));
    }


    return(true);
}


void WnnInstance::move_preedit_caret (unsigned int pos)
{
    if (!m_conversion) m_rk.setPos(pos);
    update_preedit_caret(pos);
}

void WnnInstance::select_candidate (unsigned int item)
{
    if (!m_lookup_table.number_of_candidates()) return;

    int p = m_lookup_table.get_current_page_start() + item;
    m_convList.pos = p;
    wnn.select(m_convList.pos);
    update_preedit_string(wnn.getText(),wnn.getAttributeList());
    update_preedit_caret(wnn.getCaretPos());
    m_lookup_table.set_cursor_pos(m_convList.pos);
    update_lookup_table(m_lookup_table);
}

void WnnInstance::update_lookup_table_page_size (unsigned int page_size)
{
    m_lookup_table.set_page_size (page_size);
}

void WnnInstance::lookup_table_page_up ()
{
    if (!m_lookup_table.number_of_candidates () || !m_lookup_table.get_current_page_start ()) return;

    int p = m_convList.pos - m_lookup_table.get_current_page_size();
    if (p < 0) p = 0;
    m_convList.pos = p;
    wnn.select(m_convList.pos);
    update_preedit_string(wnn.getText(),wnn.getAttributeList());
    update_preedit_caret(wnn.getCaretPos());
    m_lookup_table.set_cursor_pos(m_convList.pos);
    update_lookup_table(m_lookup_table);
}

void WnnInstance::lookup_table_page_down ()
{
    if (!m_lookup_table.number_of_candidates () ||
        m_lookup_table.get_current_page_start () + m_lookup_table.get_current_page_size () >=
          m_lookup_table.number_of_candidates ())
        return;

    int p = m_convList.pos + m_lookup_table.get_current_page_size();
    if (p >= m_convList.count) p = m_convList.count - 1;
    m_convList.pos = p;
    wnn.select(m_convList.pos);
    update_preedit_string(wnn.getText(),wnn.getAttributeList());
    update_preedit_caret(wnn.getCaretPos());
    m_lookup_table.set_cursor_pos(m_convList.pos);
    update_lookup_table(m_lookup_table);
}

void WnnInstance::reset ()
{
    alp_count = 0;
    m_conversion = false;
    m_lookup = false;
    hide_lookup_table ();
    hide_aux_string();
    hide_preedit_string ();
    wnn.reset();
    m_rk.reset();
}

void WnnInstance::focus_in ()
{
}

void WnnInstance::focus_out ()
{
    if (m_conversion) {
        commit_string(wnn.getText());
        wnn.updateFrequency();
        m_rk.reset();
        wnn.reset();
        m_conversion = false;
        hide_preedit_string();
        hide_lookup_table();
        hide_aux_string();
        m_lookup = false;
        alp_count = 0;
    } else if (m_rk.getTextLength()) {
        commit_string(m_rk.getText(true));
        m_rk.reset();
        hide_preedit_string();
    }
}

void WnnInstance::trigger_property (const String &property)
{
}






/*!
    \fn WnnInstance::startConversion(WideString s)
 */
void WnnInstance::startConversion(WideString s)
{
    if (!m_connected) {
        m_connected = wnn.wnnConnect(String("test"),host,rc,0);
    }
    if (!m_connected) {
        update_aux_string(utf8_mbstowcs(String(_("could not connect to jserver."))));
        show_aux_string();
        return;
    }

    wnn.setYomiText(s);
    if (wnn.ren_conversion() == -1) {
        update_aux_string(utf8_mbstowcs(String(_("could not connect to jserver."))));
        show_aux_string();
        return;
    }
    m_convList = wnn.getConversionList();
    m_conversion = true;

    alp_count = 0;
}


/*!
    \fn WnnInstance::createLookupTable(WnnConversionList cList)
 */
void WnnInstance::createLookupTable(WnnConversionList cList)
{
    m_lookup_table.clear();
    if (!cList.count) return;
    for (unsigned int i = 0;i < cList.count;i ++) {
        m_lookup_table.append_candidate(cList.kouho.at(i));
    }
    m_lookup_table.set_cursor_pos(cList.pos);
    update_lookup_table(m_lookup_table);
}


/*!
    \fn WnnInstance::startLookup()
 */
void WnnInstance::startLookup()
{
    createLookupTable(m_convList);
    m_lookup = true;
    update_aux_string(utf8_mbstowcs(String(_("lookup result"))));
    show_aux_string();
    show_lookup_table();
}