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

// 国際化のおまじない。
#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のおまじない。
#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


static Pointer <WnnFactory> _scim_wnn_factory;
static ConfigPointer _scim_config;

extern "C" {
    void scim_module_init (void)
    {
        bindtextdomain (GETTEXT_PACKAGE, SCIM_WNN_LOCALEDIR);
        bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
    }

    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
{
    return m_name;
}

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

WideString WnnFactory::get_credits () const
{
    return WideString ();
}

WideString WnnFactory::get_help () const
{
    return utf8_mbstowcs (String (_("SCIM-WNN HELP")));
}

String WnnFactory::get_uuid () const
{
    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) {
    int kc = k.get_ascii_code();
    if ((kc > 0x60) && (kc < 0x7b)) kc -= 0x20;
    else if ((kc > 0x40) && (kc < 0x5b)) kc += 0x20;
    for (unsigned int i = 0;i < size();i ++) {
        if ((at(i).code == k.code) && (at(i).mask == k.mask)) {
            return(true);
        }
        if (kc && (at(i).code == kc) && (at(i).mask == k.mask)) {
            return(true);
        }
    }
    return(false);
}


// 現物。


WnnInstance::WnnInstance (WnnFactory *factory, const String& encoding, int id)
    : IMEngineInstanceBase (factory, encoding, id)
{
    m_iconv.set_encoding ("EUC-JP");
    preeditors.push_back(new Romkan(_scim_config));
    preeditors.push_back(new KanaInput(_scim_config));
    m_preeditor = preeditors.at(0);
    init();
}

WnnInstance::~WnnInstance()
{
    for(unsigned int i = 0;i < preeditors.size();i ++) {
        delete(preeditors.at(i));
    }
    if (wnn.isConnected()) wnn.wnnDisconnect();
}


/*!
    \fn WnnInstance::init()
 */
void WnnInstance::init()
{
    m_conversion = false;
    m_yosoku = false;
    m_lookup = false;

    // @todo if connected to jserver, should disconnect this.

    host = _scim_config->read(String(SCIM_CONFIG_WNN_SERVER),String(SCIM_DEFAULT_WNN_SERVER));
    rc = _scim_config->read(String(SCIM_CONFIG_WNN_RC),String(SCIM_DEFAULT_WNN_RC));
    alp = _scim_config->read(String(SCIM_CONFIG_WNN_ALP),SCIM_DEFAULT_WNN_ALP);
    mini_status = _scim_config->read(String(SCIM_CONFIG_WNN_MINISTATUS),SCIM_DEFAULT_WNN_MINISTATUS);
    numkeyselect = _scim_config->read(String(SCIM_CONFIG_WNN_NUMKEY_SELECT),SCIM_DEFAULT_WNN_NUMKEY_SELECT);
    yosoku = _scim_config->read(String(SCIM_CONFIG_WNN_YOSOKU),SCIM_DEFAULT_WNN_YOSOKU);
    String t = _scim_config->read(String(SCIM_CONFIG_WNN_SERVERTYPE),String(SCIM_DEFAULT_WNN_SERVERTYPE));

    if (t == "Wnn6") {
        sType = Wnn6;
    } else if (t == "Wnn7") {
        sType = Wnn7;
    } else if (t == "Wnn8") {
        sType = Wnn8;
    } else {
        sType = Wnn4;
    }

    defaultPreEditor = _scim_config->read(String(SCIM_CONFIG_WNN_DEFAULT_PREEDITOR),String(SCIM_DEFAULT_WNN_DEFAULT_PREEDITOR));
    auto_conversion = _scim_config->read(String(SCIM_CONFIG_WNN_AUTO_CONVERSION),SCIM_DEFAULT_WNN_AUTO_CONVERSION);;

    // デフォルトキー設定。
    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_home,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_HOME),
            String(SCIM_DEFAULT_WNN_KEY_HOME)));
    scim_string_to_key_list(k_end,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_END),
            String(SCIM_DEFAULT_WNN_KEY_END)));
    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)));
    scim_string_to_key_list(k_convert_hiragana,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERT_HIRAGANA),
            String(SCIM_DEFAULT_WNN_KEY_CONVERT_HIRAGANA)));
    scim_string_to_key_list(k_convert_katakana,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERT_KATAKANA),
            String(SCIM_DEFAULT_WNN_KEY_CONVERT_KATAKANA)));
    scim_string_to_key_list(k_convert_half,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERT_HALF),
            String(SCIM_DEFAULT_WNN_KEY_CONVERT_HALF)));
    scim_string_to_key_list(k_convert_wide,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERT_WIDE),
            String(SCIM_DEFAULT_WNN_KEY_CONVERT_WIDE)));

    scim_string_to_key_list(k_conversion_rensou,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_RENSOU),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_RENSOU)));
    scim_string_to_key_list(k_conversion_ikeiji,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_CONVERSION_IKEIJI),
            String(SCIM_DEFAULT_WNN_KEY_CONVERSION_IKEIJI)));
    scim_string_to_key_list(k_select_yosoku,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_SELECT_YOSOKU),
            String(SCIM_DEFAULT_WNN_KEY_SELECT_YOSOKU)));
    scim_string_to_key_list(k_auto_conversion,
        _scim_config->read(String(SCIM_CONFIG_WNN_KEY_AUTO_CONVERSION),
            String(SCIM_DEFAULT_WNN_KEY_AUTO_CONVERSION)));

    changePreEditor(defaultPreEditor);

    // ここで一度接続しておこう。
    wnn.wnnConnect(String("scim-wnn"),host,rc,sType,0);

}


/*!
    \fn WnnInstance::changePreEditor(const String &name)
 */
void WnnInstance::changePreEditor(const String &name)
{
    for(unsigned int i = 0;i < preeditors.size();i ++) {
        if (preeditors[i]->getPropertyName() == name) {
            m_preeditor = preeditors[i];
            return;
        }
    }
    return;
}


/*!
    \fn WnnInstance::updateProperty()
 */
void WnnInstance::updateProperty()
{
    if (m_proplist.empty()) {
        Property p;
        p = Property(SCIM_PROP_WNN_INPUTMODE,"",String(""),_("input mode"));
        m_proplist.push_back(p);
        for(unsigned int i = 0;i < preeditors.size();i ++) {
            p = Property(String(SCIM_PROP_WNN_INPUTMODE) + String("/") + preeditors[i]->getPropertyName(),
                preeditors[i]->getName(),String(""),_("mode status"));
            m_proplist.push_back(p);
        }
        p = Property(SCIM_PROP_WNN_MODESTATUS,"",String(""),_("mode status"));
        m_proplist.push_back(p);
        p = Property(SCIM_PROP_WNN_CONVERSIONMODE,"",String(""),_("conversion mode"));
        m_proplist.push_back(p);
    }
    PropertyList::iterator it;
    it = find(m_proplist.begin(),m_proplist.end(),SCIM_PROP_WNN_INPUTMODE);
    if (it != m_proplist.end()) {
        it->set_label(m_preeditor->getName());
    }
    update_property(*it);
    it = find(m_proplist.begin(),m_proplist.end(),SCIM_PROP_WNN_MODESTATUS);
    if (it != m_proplist.end()) {
        if (m_conversion) it->set_label(_("Kanji"));
        else if (m_yosoku) it->set_label(_("Yosoku"));
        else it->set_label(m_preeditor->getModeName());
    }
    update_property(*it);
    it = find(m_proplist.begin(),m_proplist.end(),SCIM_PROP_WNN_CONVERSIONMODE);
    if (it != m_proplist.end()) {
        if (auto_conversion) it->set_label(_("AUTO"));
        else  it->set_label(_("REN"));
    }
    update_property(*it);
    register_properties(m_proplist);
}


/*!
    \fn WnnInstance::updatePreEditor()
 */
void WnnInstance::updatePreEditor()
{
    if (m_preeditor->getTextLength()) {
        if (auto_conversion && (m_preeditor->getTextLength() == m_preeditor->getPos()))
            autoConversion();
        else {
            show_preedit_string();
            update_preedit_string(m_preeditor->getText());
            update_preedit_caret(m_preeditor->getPos());
        }
        if ((!m_conversion) && yosoku && wnn.isConnected() && (sType == Wnn7) && (!auto_conversion)) {
            m_convList = wnn.getYosokuList(m_preeditor->getText());
            if (m_convList.count) {
                m_lookup_table.clear();
                for(unsigned int i = 0;i < m_convList.count;i ++) {
                    m_lookup_table.append_candidate(m_convList.kouho.at(i));
                }
                startLookup();
            } else {
                //m_lookup_table.clear();
                hide_lookup_table();
            }
        } else hide_lookup_table();
    } else {
        hide_preedit_string();
        hide_lookup_table();
    }
    if (mini_status) {
        update_aux_string(utf8_mbstowcs(m_preeditor->getModeName()));
        show_aux_string();
    } else {
        hide_aux_string();
    }

    updateProperty();
}
/*!
    \fn WnnInstance::updateConversion()
 */
void WnnInstance::updateConversion()
{
    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);
        show_lookup_table();
    } else {
        hide_lookup_table();
        hide_aux_string();
    }
    updateProperty();
}


bool WnnInstance::process_key_event (const KeyEvent& key)
{
    if (key.is_key_release()) return(false);
    KeyEvent ke = key;
    if (ke.mask & SCIM_KEY_CapsLockMask) ke.mask -= SCIM_KEY_CapsLockMask;
    if (ke.mask & SCIM_KEY_NumLockMask) ke.mask -= SCIM_KEY_NumLockMask;
    if (ke.mask & SCIM_KEY_ScrollLockMask) ke.mask -= SCIM_KEY_ScrollLockMask;
    if (m_conversion) return(process_conversion_key_event(ke));
    else if (m_yosoku) return(process_yosoku_key_event(ke));
    else return(process_preedit_key_event(ke));
}


/*!
    \fn WnnInstance::process_preedit_key_event(const KeyEvent &key)
 */
bool WnnInstance::process_preedit_key_event(const KeyEvent &key)
{
    // PreEditorのキーイベントフック。
    if (m_preeditor->keyEventHook(key)) {
        updatePreEditor();
        return(true);
    } else

    // バッファが空では無い場合。
    if (m_preeditor->getTextLength()) {
        if (k_conversion_start.comp(key)) {
            startConversion(m_preeditor->getText(true));
            alp_count ++;
            return(true);
        } else
        if (k_commit.comp(key)) {
            if (auto_conversion) {
                commit_string(wnn.getText());
                wnn.reset();
            } else commit_string(m_preeditor->getText(true));
            m_preeditor->reset();
            updatePreEditor();
            return(true);
        } else
        if (k_forward.comp(key) || k_backward.comp(key)) {
            k_backward.comp(key) ? m_preeditor->setPos(m_preeditor->getPos() - 1) : m_preeditor->setPos(m_preeditor->getPos() + 1);
            updatePreEditor();
            return(true);
        } else
        if (k_home.comp(key) || k_end.comp(key)) {
            k_end.comp(key) ? m_preeditor->setPos(m_preeditor->getTextLength()) : m_preeditor->setPos(0);
            updatePreEditor();
            return(true);
        } else
        if ((k_backspace.comp(key)) || (k_delete.comp(key))) {
            k_backspace.comp(key) ? m_preeditor->backspace(): m_preeditor->del();
            updatePreEditor();
            return(true);
        } else
        if (k_convert_hiragana.comp(key)) {
            m_preeditor->kataHira();
            updatePreEditor();
            return(true);
        } else
        if (k_convert_katakana.comp(key)) {
            m_preeditor->hiraKata();
            updatePreEditor();
            return(true);
        } else
        if (k_convert_half.comp(key)) {
            m_preeditor->toHalf();
            updatePreEditor();
            return(true);
        } else
        if (k_convert_wide.comp(key)) {
            m_preeditor->toWide();
            updatePreEditor();
            return(true);
        } else
        if (k_select_yosoku.comp(key) && yosoku) {
            if ((m_convList.kType == YOSOKU) && (m_convList.count)) {
                return(process_yosoku_key_event(key));
            }
        }
    }

    // バッファの存在にかかわらず。
    if (k_cancel.comp(key)) {
        if (m_preeditor->cancelEvent()) {
            updatePreEditor();
            return(true);
        }
        if (m_preeditor->getTextLength()) {
            m_preeditor->reset();
        }
        updatePreEditor();
        return(true);
    }

    if (k_auto_conversion.comp(key)) {
        auto_conversion ? auto_conversion = false : auto_conversion = true;
        updatePreEditor();
        return(true);
    }

    if (m_preeditor->inputEvent(key)) {
        updatePreEditor();

        return(true);
    } else {
        // preeditorで処理できなかった場合はやはりcommitしてアプリケーションに返すべきだ。
        if (m_preeditor->getTextLength()) {
            if (auto_conversion) {
                commit_string(wnn.getText());
                wnn.reset();
            } else commit_string(m_preeditor->getText(true));
        }
        m_preeditor->reset();
        updatePreEditor();
    }

    return(false);
}

/*!
    \fn WnnInstance::process_conversion_key_event(const KeyEvent &key)
 */
bool WnnInstance::process_conversion_key_event(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 ((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_preeditor->reset();
        wnn.reset();
        m_conversion = false;
        updatePreEditor();
        m_lookup = false;
        alp_count = 1;
        return(true);
    } else
    if (k_cancel.comp(key) || k_backspace.comp(key)) {
        wnn.reset();
        m_conversion = false;
        m_lookup = false;
        alp_count = 0;
        updatePreEditor();
        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);
        updateConversion();
        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();
        if (alp == -1) {
            startLookup();
        } else m_lookup = false;
        updateConversion();
        alp_count = 1;
        return(true);
    } else
    if (k_conversion_rensou.comp(key) && ((sType == Wnn7) || (sType == Wnn8)) ) {
        m_convList = wnn.getConversionList(wnn.getPos(),RENSOU);
        if (m_convList.count == 0) return(true);
        startLookup();
        updateConversion();
        alp_count = 1;
        return(true);
    } else
    if (k_conversion_ikeiji.comp(key) && ((sType == Wnn7) || (sType == Wnn8)) ) {
        m_convList = wnn.getConversionList(wnn.getPos(),IKEIJI);
        if (m_convList.count == 0) return(true);
        startLookup();
        updateConversion();
        alp_count = 1;
        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();
        if (alp == -1) {
            startLookup();
        } else m_lookup = false;
        updateConversion();
        alp_count = 1;
        return(true);
    } else
    if (k_convert_hiragana.comp(key) || k_convert_katakana.comp(key)) {
        WideString res = m_convList.Yomi;
        k_convert_hiragana.comp(key) ? m_preeditor->convKataHira(res) : m_preeditor->convHiraKata(res);
        for(unsigned int i = 0;i < m_convList.count;i ++) {
            if (res == m_convList.kouho[i]) {
                m_convList.pos = i;
                wnn.select(m_convList.pos);
                updateConversion();
                break;
            }
        }
        return(true);
    } else
    if (key.get_ascii_code()) {
        if (key.mask & (SCIM_KEY_AltMask | SCIM_KEY_ControlMask)) return(false);
            if (m_lookup && numkeyselect) {
                char numk[] = "1234567890";
                int numc = 0;
                bool numkey = false;
                for(;numk[numc]; ++ numc) {
                    if (key.get_ascii_code() == numk[numc]) {
                        numkey = true;
                        break;
                    }
                }
                if (numkey) {
                    if (m_lookup_table.get_current_page_size() < numc) return(true);
                    m_convList.pos = numc + m_lookup_table.get_current_page_start();
                    wnn.select(m_convList.pos);
                    wnn.setPos(wnn.getPos() + 1);
                    m_convList = wnn.getConversionList();
                    updateConversion();
                    startLookup();
                    return(true);
                }
            }

        commit_string(wnn.getText());
        wnn.updateFrequency();
        m_preeditor->reset();
        wnn.reset();
        m_conversion = false;
        m_lookup = false;
        alp_count = 0;
        updatePreEditor();
        return(process_preedit_key_event(key));
    }


    return(true);
}



/*!
    \fn WnnInstance::process_yosoku_key_event(const KeyEvent &key)
 */
bool WnnInstance::process_yosoku_key_event(const KeyEvent &key)
{
    if (!m_yosoku) {
        m_yosoku = true;
        update_preedit_string(m_convList.kouho.at(m_convList.pos));
        update_preedit_caret(0);
        show_preedit_string();
        updateProperty();
        return(true);
    }

    if (k_lookup_pageup.comp(key)) {
        lookup_table_page_up();
        return(true);
    } else
    if (k_lookup_pagedown.comp(key)) {
        lookup_table_page_down();
        return(true);
    } else
    if (k_conversion_next.comp(key) || k_conversion_prev.comp(key) || k_select_yosoku.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;
        m_lookup_table.set_cursor_pos(m_convList.pos);
        update_lookup_table(m_lookup_table);
        update_preedit_string(m_convList.kouho.at(m_convList.pos));
        update_preedit_caret(0);
//        select_candidate((unsigned int)m_convList.pos);
        updateProperty();
        return(true);
    } else
    if (k_commit.comp(key)) {
        m_yosoku = false;
        commit_string(m_convList.kouho.at(m_convList.pos));
        m_preeditor->reset();
        updatePreEditor();
        return(true);
    } else
    if (k_cancel.comp(key) || k_backspace.comp(key)) {
        m_yosoku = false;
        updatePreEditor();
        return(true);
    }
    if (!key.get_ascii_code()) return(true);
    if ((!(key.is_control_down() || key.is_alt_down() || key.is_shift_down())) && numkeyselect) {
        char numk[] = "1234567890";
        for(int numc = 0;numk[numc]; ++ numc) {
            if (key.get_ascii_code() == numk[numc]) {
                if (m_lookup_table.get_current_page_size() > numc)
                    select_candidate((unsigned int)numc);
                return(true);
            }
        }
    }

    m_yosoku = false;
    commit_string(m_convList.kouho.at(m_convList.pos));
    m_preeditor->reset();
    updatePreEditor();
    return(process_preedit_key_event(key));
}



void WnnInstance::move_preedit_caret (unsigned int pos)
{
    //if (!m_conversion) m_preeditor->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);
    if (m_convList.kType != YOSOKU) {
        update_preedit_string(wnn.getText(),wnn.getAttributeList());
        update_preedit_caret(wnn.getCaretPos());
    } else {
        update_preedit_string(m_convList.kouho.at(m_convList.pos));
        update_preedit_caret(0);
        if (!m_yosoku) {
            // マウスで選択した場合は予測選択モードに突入。
            m_yosoku = true;
            show_preedit_string();
            updateProperty();
        }
    }
    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 ()
{
    // Qt-immodule+scim-qtimmではこのメソッドが大量に呼ばれるようだが、他ではどうなのか?。
    alp_count = 0;
    m_conversion = false;
    m_lookup = false;
    wnn.reset();
    m_preeditor->reset();
    //if (wnn.isConnected()) wnn.wnnDisconnect();
    //wnn.wnnConnect(String("scim-wnn"),host,rc,sType,0);
    //updatePreEditor();
}

void WnnInstance::focus_in ()
{
    if (!m_conversion) updatePreEditor();
    else updateProperty();
}

void WnnInstance::focus_out ()
{
    if (m_conversion) {
        commit_string(wnn.getText());
        wnn.updateFrequency();
        wnn.reset();
        m_conversion = false;
        m_lookup = false;
        alp_count = 0;
    } else if (m_preeditor->getTextLength()) {
        commit_string(m_preeditor->getText(true));
    }
    m_preeditor->reset();
    updatePreEditor();
}

void WnnInstance::trigger_property (const String &property)
{
    String s = SCIM_PROP_WNN_INPUTMODE;
    if ((property.length() > s.length()) && (property.substr(0,s.length()) == s)) {
        changePreEditor(property.substr(s.length() + 1));
        updateProperty();
    }
    s = SCIM_PROP_WNN_CONVERSIONMODE;
    if (property == s) {
        auto_conversion ? auto_conversion = false : auto_conversion = true;
        updatePreEditor();
    }
}






/*!
    \fn WnnInstance::startConversion(WideString s)
 */
void WnnInstance::startConversion(WideString s)
{
    // 一度lookupは消しておこう。
    m_lookup = false;
    m_lookup_table.clear();
    hide_lookup_table();

    hide_aux_string();
    if (!wnn.isConnected()) {
        if (!wnn.wnnConnect(String("scim-wnn"),host,rc,sType,0)) {
            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.kouho.clear();
    m_convList = wnn.getConversionList();
    m_conversion = true;

    alp_count = 1;

    show_preedit_string();
    update_preedit_string(wnn.getText(),wnn.getAttributeList());
    update_preedit_caret(wnn.getCaretPos());
    if (alp == -1) {
        startLookup();
    }
    updateProperty();
}


/*!
    \fn WnnInstance::autoConversion()
 */
void WnnInstance::autoConversion()
{
    if (!wnn.isConnected()) {
        if (!wnn.wnnConnect(String("scim-wnn"),host,rc,sType,0)) {
            update_aux_string(utf8_mbstowcs(String(_("could not connect to jserver."))));
            show_aux_string();
            show_preedit_string();
            update_preedit_string(m_preeditor->getText());
            update_preedit_caret(m_preeditor->getPos());
            return;
        }
    }

    wnn.reset();
    wnn.setYomiText(m_preeditor->getText(true));
    if (wnn.ren_conversion() == -1) {
        update_aux_string(utf8_mbstowcs(String(_("could not connect to jserver."))));
        show_aux_string();
        show_preedit_string();
        update_preedit_string(m_preeditor->getText());
        update_preedit_caret(m_preeditor->getPos());
        return;
    }

    show_preedit_string();
    update_preedit_string(wnn.getText());
    update_preedit_caret(wnn.getText().size());
}


/*!
    \fn WnnInstance::createLookupTable(WnnConversionList cList)
 */
void WnnInstance::createLookupTable(WnnConversionList cList)
{
    hide_lookup_table();
    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);
    if (m_convList.count == 0) return;
    m_lookup = true;
    switch(m_convList.kType) {
        case IKEIJI: {
            update_aux_string(utf8_mbstowcs(String(_("Ikeiji lookup result"))));
            break;
        }
        case RENSOU: {
            update_aux_string(utf8_mbstowcs(String(_("association lookup result"))));
            break;
        }
        case YOSOKU: {
            update_aux_string(utf8_mbstowcs(String(_("yosoku lookup result"))));
            break;
        }
        default: {
            update_aux_string(utf8_mbstowcs(String(_("lookup result"))));
            break;
        }
    }
    show_aux_string();
    show_lookup_table();
}