/*************************************************************************** * 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. * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <sys/types.h> #include <dirent.h> #include <set> // 国際化のおまじない。 #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 "honoka_imengine.h" #include "honokatimer.h" #include "honoka_def.h" #define scim_module_init honoka_LTX_scim_module_init #define scim_module_exit honoka_LTX_scim_module_exit #define scim_imengine_module_init honoka_LTX_scim_imengine_module_init #define scim_imengine_module_create_factory honoka_LTX_scim_imengine_module_create_factory #ifndef HONOKA_ICON_FILE #define HONOKA_ICON_FILE (SCIM_ICONDIR "/honoka.png") #endif #ifndef PACKAGE_STRING #define PACKAGE_STRING "honoka" #endif static Pointer <HonokaFactory> _honoka_factory; static ConfigPointer _scim_config; extern "C" { void scim_module_init (void) { bindtextdomain (GETTEXT_PACKAGE, HONOKA_LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); } void scim_module_exit (void) { _honoka_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 (_honoka_factory.null ()) { _honoka_factory = new HonokaFactory (utf8_mbstowcs (String (_("Honoka"))),String("ja_JP")); } return _honoka_factory; } } HonokaFactory::HonokaFactory() { m_name = utf8_mbstowcs(_("Honoka")); set_languages(String("ja_JP")); } HonokaFactory::~ HonokaFactory() { } HonokaFactory::HonokaFactory(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 HonokaFactory::get_name () const { return m_name; } WideString HonokaFactory::get_authors () const { return utf8_mbstowcs (String (_("(C)2004-2006 TAM(Teppei Tamra) <tam-t@par.odn.ne.jp>"))); } WideString HonokaFactory::get_credits () const { return WideString (); } WideString HonokaFactory::get_help () const { return utf8_mbstowcs (String(PACKAGE_STRING) + String("\n") + String(_("HONOKA-HELP"))); } String HonokaFactory::get_uuid () const { return String ("8bb03c1c-db6c-41b1-91bd-b7fb7dd70343"); } String HonokaFactory::get_icon_file () const { return String (HONOKA_ICON_FILE); } IMEngineInstancePointer HonokaFactory::create_instance (const String& encoding, int id) { return new HonokaInstance (this, encoding, id); } // 現物。 HonokaInstance::HonokaInstance (HonokaFactory *factory, const String& encoding, int id) : IMEngineInstanceBase (factory, encoding, id) { m_iconv.set_encoding ("EUC-JP"); // 初期化へ。 loadPlugins(); init(); } HonokaInstance::~HonokaInstance() { if (save_setting) { _scim_config->write(String(HONOKA_PREVIOUS_PREEDITOR),m_preeditor->getName()); _scim_config->write(String(HONOKA_PREVIOUS_PREDICTOR),m_predictor->getName()); _scim_config->write(String(HONOKA_PREVIOUS_CONVERTOR),m_convertor->getName()); } unload(); } /*! \fn HonokaInstance::split(const String &str,const char &sep) */ vector<String> HonokaInstance::split(const String &str,const char &sep) { vector<String> s; String w; for(unsigned int i = 0;i < str.length();i ++) { if (str[i] == sep) { if (w.length()) { s.push_back(w); w.clear(); } } else w = w + str.substr(i,1); } if (w.length()) s.push_back(w); return s; } bool HonokaInstance::pluginCheck(HonokaPluginBase *p) { // Convertorの場合。 if (p->getPluginType() == "Convertor") { convertors.push_back(static_cast<Convertor *>(p)); return true; } else // PreEditorの場合。 if (p->getPluginType() == "PreEditor") { preeditors.push_back(static_cast<PreEditor *>(p)); return true; } else // Predictorの場合。 if (p->getPluginType() == "Predictor") { predictors.push_back(static_cast<Predictor *>(p)); return true; } return false; } /*! \fn HonokaInstance::loadPlugins() */ void HonokaInstance::loadPlugins() { DIR *dir = opendir(HONOKA_PLUGINDIR); if (dir) { struct dirent *entry; // // プラグイン読み込み部分。 // set<String> pluginNameList; while((entry = readdir(dir)) != NULL) { // まず名前を決定します。 String d = entry->d_name; if ((d.substr(0,6) == "plugin") && (d.substr(d.length() - 3,3) == ".so")) { if (!_scim_config->read(String(HONOKA_CONFIG_PLUGINLOADER_PREFIX) + "/" + d.substr(0,d.length() - 3),true)) continue; d = String(HONOKA_PLUGINDIR) + "/" + d; // 実際にロードします。 void* plugin = dlopen(d.c_str(), RTLD_LAZY); if (!plugin) continue; // 関数を抜き取ります。 createInstanceFunc *getInstance = (createInstanceFunc *)dlsym(plugin,"getHonokaPluginInstance"); deleteInstanceFunc *deleteInstance = (deleteInstanceFunc *)dlsym(plugin,"deleteHonokaPluginInstance"); getPluginVersionFunc *getPluginVersion = (getPluginVersionFunc *)dlsym(plugin,"getHonokaPluginVersion"); // 関数が不足した場合はアンロードします。 if ((!getInstance) || (!deleteInstance) || (!getPluginVersion)) { dlclose(plugin); continue; } // バージョンチェックします。 if (getPluginVersion() == HONOKA_PLUGIN_VERSION) { // いきなりインスタンスをゲトします。 HonokaPluginBase *p = getInstance(_scim_config); // プラグイン情報を得ておきます。 HonokaPluginEntry pe; pe.filename = d; pe.createInstance = getInstance; pe.deleteInstance = deleteInstance; pe.getPluginVersion = getPluginVersion; pe.instance = p; pe.name = p->getName(); pe.dll = plugin; // 同名のプラグインがあった場合はロードを中止します。 if (pluginNameList.find(p->getName()) != pluginNameList.end()) { deleteInstance(p); dlclose(plugin); } else if (p->getPluginType() == "Multiple") { plugins.push_back(pe); pluginNameList.insert(p->getName()); for(unsigned int i = 0;i < static_cast<HonokaMultiplePluginBase *>(p)->getPluginCount();i++) pluginCheck(static_cast<HonokaMultiplePluginBase *>(p)->getPluginInstanceAt(i)); } else if (pluginCheck(p)) { plugins.push_back(pe); pluginNameList.insert(p->getName()); } else { deleteInstance(p); dlclose(plugin); } } else { dlclose(plugin); } } } closedir(dir); } acpredictor = new ACPredictor(_scim_config,this); predictors.push_back(acpredictor); // プラグインがなければデフォの低機能なベースクラスを使います。 if (!convertors.size()) convertors.push_back(new Convertor(_scim_config)); if (!preeditors.size()) preeditors.push_back(new PreEditor(_scim_config)); if (!predictors.size()) predictors.push_back(new Predictor(_scim_config)); // 初期利用Convertor/PreEditorを指定します。 m_convertor = convertors.at(0); m_preeditor = preeditors.at(0); m_predictor = predictors.at(0); m_multi = new MultiConvertor(_scim_config,this); return; } /*! \fn HonokaInstance::unload() */ void HonokaInstance::unload() { HonokaTimer::destruct(); m_preeditor->reset(); for(unsigned int i = 0;i < plugins.size();i ++) { plugins[i].deleteInstance(plugins[i].instance); dlclose(plugins[i].dll); } convertors.clear(); preeditors.clear(); predictors.clear(); delete acpredictor; delete m_multi; plugins.clear(); } /*! \fn HonokaInstance::init() */ void HonokaInstance::init() { // 初期化。 m_conversion = false; m_prediction = false; m_lookup = false; while(preeditStack.size()) { preeditStack.pop(); } // @todo if connected to jserver, should disconnect this. alp = _scim_config->read(String(HONOKA_CONFIG_ALP),HONOKA_DEFAULT_ALP); mini_status = _scim_config->read(String(HONOKA_CONFIG_MINISTATUS),HONOKA_DEFAULT_MINISTATUS); numkeyselect = _scim_config->read(String(HONOKA_CONFIG_NUMKEY_SELECT),HONOKA_DEFAULT_NUMKEY_SELECT); prediction = _scim_config->read(String(HONOKA_CONFIG_PREDICTION),HONOKA_DEFAULT_PREDICTION); realtime_prediction = _scim_config->read(String(HONOKA_CONFIG_REALTIME_PREDICTION),HONOKA_DEFAULT_REALTIME_PREDICTION); changeable_splitter = _scim_config->read(String(HONOKA_CONFIG_CHANGEABLE_SPLITTER),HONOKA_DEFAULT_CHANGEABLE_SPLITTER); if (m_predictor->getName() == "Predictor") prediction = false; defaultPreEditor = _scim_config->read(String(HONOKA_CONFIG_DEFAULT_PREEDITOR),String(HONOKA_DEFAULT_DEFAULT_PREEDITOR)); defaultConvertor = _scim_config->read(String(HONOKA_CONFIG_DEFAULT_CONVERTOR),String(HONOKA_DEFAULT_DEFAULT_CONVERTOR)); defaultPredictor = _scim_config->read(String(HONOKA_CONFIG_DEFAULT_PREDICTOR),String(HONOKA_DEFAULT_DEFAULT_PREDICTOR)); auto_conversion = _scim_config->read(String(HONOKA_CONFIG_AUTO_CONVERSION),HONOKA_DEFAULT_AUTO_CONVERSION);; predictionDelay = _scim_config->read(String(HONOKA_CONFIG_PREDICTION_DELAY),HONOKA_DEFAULT_PREDICTION_DELAY); save_setting = _scim_config->read(String(HONOKA_CONFIG_SAVE_SETTING),HONOKA_DEFAULT_SAVE_SETTING); select_prediction_direct = _scim_config->read(String(HONOKA_CONFIG_SELECT_PREDICTION_DIRECT),HONOKA_DEFAULT_SELECT_PREDICTION_DIRECT); // デフォルトキー設定。 scim_string_to_key_list(k_conversion_start, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_START), String(HONOKA_DEFAULT_KEY_CONVERSION_START))); scim_string_to_key_list(k_cancel, _scim_config->read(String(HONOKA_CONFIG_KEY_CANCEL), String(HONOKA_DEFAULT_KEY_CANCEL))); scim_string_to_key_list(k_delete, _scim_config->read(String(HONOKA_CONFIG_KEY_DELETE), String(HONOKA_DEFAULT_KEY_DELETE))); scim_string_to_key_list(k_backspace, _scim_config->read(String(HONOKA_CONFIG_KEY_BACKSPACE), String(HONOKA_DEFAULT_KEY_BACKSPACE))); scim_string_to_key_list(k_commit, _scim_config->read(String(HONOKA_CONFIG_KEY_COMMIT), String(HONOKA_DEFAULT_KEY_COMMIT))); scim_string_to_key_list(k_furigana_commit, _scim_config->read(String(HONOKA_CONFIG_KEY_FURIGANA_COMMIT), String(HONOKA_DEFAULT_KEY_FURIGANA_COMMIT))); scim_string_to_key_list(k_conversion_next, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_NEXT), String(HONOKA_DEFAULT_KEY_CONVERSION_NEXT))); scim_string_to_key_list(k_conversion_prev, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_PREV), String(HONOKA_DEFAULT_KEY_CONVERSION_PREV))); scim_string_to_key_list(k_conversion_expand, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_EXPAND), String(HONOKA_DEFAULT_KEY_CONVERSION_EXPAND))); scim_string_to_key_list(k_conversion_shrink, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_SHRINK), String(HONOKA_DEFAULT_KEY_CONVERSION_SHRINK))); scim_string_to_key_list(k_conversion_forward, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_FORWARD), String(HONOKA_DEFAULT_KEY_CONVERSION_FORWARD))); scim_string_to_key_list(k_conversion_backward, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_BACKWARD), String(HONOKA_DEFAULT_KEY_CONVERSION_BACKWARD))); scim_string_to_key_list(k_forward, _scim_config->read(String(HONOKA_CONFIG_KEY_FORWARD), String(HONOKA_DEFAULT_KEY_FORWARD))); scim_string_to_key_list(k_backward, _scim_config->read(String(HONOKA_CONFIG_KEY_BACKWARD), String(HONOKA_DEFAULT_KEY_BACKWARD))); scim_string_to_key_list(k_home, _scim_config->read(String(HONOKA_CONFIG_KEY_HOME), String(HONOKA_DEFAULT_KEY_HOME))); scim_string_to_key_list(k_end, _scim_config->read(String(HONOKA_CONFIG_KEY_END), String(HONOKA_DEFAULT_KEY_END))); scim_string_to_key_list(k_lookup_popup, _scim_config->read(String(HONOKA_CONFIG_KEY_LOOKUPPOPUP), String(HONOKA_DEFAULT_KEY_LOOKUPPOPUP))); scim_string_to_key_list(k_lookup_pageup, _scim_config->read(String(HONOKA_CONFIG_KEY_LOOKUPPAGEUP), String(HONOKA_DEFAULT_KEY_LOOKUPPAGEUP))); scim_string_to_key_list(k_lookup_pagedown, _scim_config->read(String(HONOKA_CONFIG_KEY_LOOKUPPAGEDOWN), String(HONOKA_DEFAULT_KEY_LOOKUPPAGEDOWN))); scim_string_to_key_list(k_convert_ctype, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERT_CTYPETOGGLE), String(HONOKA_DEFAULT_KEY_CONVERT_CTYPETOGGLE))); scim_string_to_key_list(k_convert_hiragana, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERT_HIRAGANA), String(HONOKA_DEFAULT_KEY_CONVERT_HIRAGANA))); scim_string_to_key_list(k_convert_katakana, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERT_KATAKANA), String(HONOKA_DEFAULT_KEY_CONVERT_KATAKANA))); scim_string_to_key_list(k_convert_half, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERT_HALF), String(HONOKA_DEFAULT_KEY_CONVERT_HALF))); scim_string_to_key_list(k_convert_wide, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERT_WIDE), String(HONOKA_DEFAULT_KEY_CONVERT_WIDE))); scim_string_to_key_list(k_conversion_rensou, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_RENSOU), String(HONOKA_DEFAULT_KEY_CONVERSION_RENSOU))); scim_string_to_key_list(k_conversion_ikeiji, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERSION_IKEIJI), String(HONOKA_DEFAULT_KEY_CONVERSION_IKEIJI))); scim_string_to_key_list(k_select_prediction, _scim_config->read(String(HONOKA_CONFIG_KEY_SELECT_PREDICTION), String(HONOKA_DEFAULT_KEY_SELECT_PREDICTION))); scim_string_to_key_list(k_auto_conversion, _scim_config->read(String(HONOKA_CONFIG_KEY_AUTO_CONVERSION), String(HONOKA_DEFAULT_KEY_AUTO_CONVERSION))); scim_string_to_key_list(k_next_convertor, _scim_config->read(String(HONOKA_CONFIG_KEY_NEXT_CONVERTOR), String(HONOKA_DEFAULT_KEY_NEXT_CONVERTOR))); scim_string_to_key_list(k_prev_convertor, _scim_config->read(String(HONOKA_CONFIG_KEY_PREV_CONVERTOR), String(HONOKA_DEFAULT_KEY_PREV_CONVERTOR))); scim_string_to_key_list(k_reconversion, _scim_config->read(String(HONOKA_CONFIG_KEY_RECONVERSION), String(HONOKA_DEFAULT_KEY_RECONVERSION))); scim_string_to_key_list(k_result_to_preedit, _scim_config->read(String(HONOKA_CONFIG_KEY_RESULTTOPREEDIT), String(HONOKA_DEFAULT_KEY_RESULTTOPREEDIT))); scim_string_to_key_list(k_multi_conversion, _scim_config->read(String(HONOKA_CONFIG_KEY_MULTI_CONVERSION), String(HONOKA_DEFAULT_KEY_MULTI_CONVERSION))); scim_string_to_key_list(k_allreset, _scim_config->read(String(HONOKA_CONFIG_KEY_ALLRESET), String(HONOKA_DEFAULT_KEY_ALLRESET))); for(unsigned i = 0;i < 10;i ++) { char a[3]; sprintf(a,"%d",i); scim_string_to_key_list(k_selection[i], _scim_config->read(String(HONOKA_CONFIG_KEY_SELECTION_PREFIX) + String(a), String(a))); } vector<String> sl; sl = split(defaultPreEditor); for(unsigned int i = 0;i < sl.size();i ++) if (changePreEditor(sl[i])) break; sl = split(defaultConvertor); for(unsigned int i = 0;i < sl.size();i ++) if (changeConvertor(sl[i])) break; sl = split(defaultPredictor); for(unsigned int i = 0;i < sl.size();i ++) if (changePredictor(sl[i])) break; for(unsigned int i = 0;i < convertors.size();i ++) { HonokaKeyEventList k; scim_string_to_key_list(k, _scim_config->read(String(HONOKA_CONFIG_KEY_CONVERTOR_PREFIX) + String("/") + convertors[i]->getName(),String(""))); k_convertor.push_back(k); } for(unsigned int i = 0;i < preeditors.size();i ++) { HonokaKeyEventList k; scim_string_to_key_list(k, _scim_config->read(String(HONOKA_CONFIG_KEY_PREEDITOR_PREFIX) + String("/") + preeditors[i]->getName(),String(""))); k_preeditor.push_back(k); } for(unsigned int i = 0;i < predictors.size();i ++) { HonokaKeyEventList k; scim_string_to_key_list(k, _scim_config->read(String(HONOKA_CONFIG_KEY_PREDICTOR_PREFIX) + String("/") + predictors[i]->getName(),String(""))); k_predictor.push_back(k); } if (save_setting) { changePreEditor(_scim_config->read(String(HONOKA_PREVIOUS_PREEDITOR),String())); changePredictor(_scim_config->read(String(HONOKA_PREVIOUS_PREDICTOR),String())); changeConvertor(_scim_config->read(String(HONOKA_PREVIOUS_CONVERTOR),String())); } m_splitter = 0; //if (changable_splitter) changeSplitter(String("AUTO")); } /*! \fn HonokaInstance::getConvertedText() */ const WideString HonokaInstance::getConvertedText() { // このかたちでは、変換動作から候補一覧を取得した上でないと結果を得られない。 // 直すべきか?。 vector<Segment> seglist = m_convertor->getSegmentList(); vector<Segment> newsegs; WideString t; for(unsigned int i = 0;i < seglist.size();i ++) { if ((i < m_convertor->getPos()) && (segments.size() > i)) { if ((seglist[i].getKanji() != segments[i].getKanji()) && (seglist[i].getYomi().length() == segments[i].getYomi().length())) newsegs.push_back(segments[i]); else newsegs.push_back(seglist[i]); } else if (i == m_convertor->getPos()) newsegs.push_back(Segment(m_convList.kouho[m_convList.pos].kanji,seglist[i].getYomi())); else newsegs.push_back(seglist[i]); } segments = newsegs; for(unsigned int i = 0;i < segments.size();i ++) { t += segments[i].getKanji(); } return t; } /*! \fn HonokaInstance::getConvertedAttributeList() */ const AttributeList HonokaInstance::getConvertedAttributeList() { AttributeList attr; int c = 0; for(unsigned int i = 0;i < segments.size();i ++) { if (m_convertor->getPos() == i) { Attribute a(c,segments[i].getKanji().length(),SCIM_ATTR_DECORATE,SCIM_ATTR_DECORATE_REVERSE); attr.push_back(a); break; } else c += segments[i].getKanji().length(); } return attr; } /*! \fn HonokaInstance::updateConvertedString() */ void HonokaInstance::updateConvertedString() { WideString w = getConvertedText(); AttributeList a = getConvertedAttributeList(); int c = 0; for(unsigned int i = 0;i < segments.size();i ++) { if (m_convertor->getPos() == i) break; else c += segments[i].getKanji().length(); } update_preedit_string(w,a); update_preedit_caret(c); } /*! \fn HonokaInstance::changePreEditor(const String &name) */ bool HonokaInstance::changePreEditor(const String &name) { // PreEditorを変更するメソッド。 for(unsigned int i = 0;i < preeditors.size();i ++) { if (preeditors[i]->getName() == name) { m_preeditor->unSelected(); m_preeditor = preeditors[i]; m_preeditor->selected(); return true; } } return false; } /*! \fn HonokaInstance::changeConvertor(const String &name) */ bool HonokaInstance::changeConvertor(const String &name) { // Convertorを変更するメソッド。 for(unsigned int i = 0;i < convertors.size();i ++) { if (convertors[i]->getName() == name) { m_convertor->unSelected(); m_convertor = convertors[i]; m_convertor->selected(); return true; } } return false; } /*! \fn HonokaInstance::changeSplitter(const String &name) */ bool HonokaInstance::changeSplitter(const String &name) { // Splitterを変更するメソッド。 if (name == "AUTO") { m_splitter = 0; return true; } for(unsigned int i = 0;i < convertors.size();i ++) { if (convertors[i]->getName() == name) { m_splitter = convertors[i]; return true; } } return false; } /*! \fn HonokaInstance::changePredictor(const String &name) */ bool HonokaInstance::changePredictor(const String &name) { // Predictorを変更するメソッド。 if (!prediction) return false; for(unsigned int i = 0;i < predictors.size();i ++) { if (predictors[i]->getName() == name) { m_predictor = predictors[i]; if (prediction && (!m_predictor->isConnected())) m_predictor->connect(); preeditCache.clear(); return true; } } return false; } /*! \fn HonokaInstance::updateProperty() */ void HonokaInstance::updateProperty() { // プロパティを更新するメソッド。 if (m_proplist.empty()) { Property p; p = Property(HONOKA_PROP_INPUTMODE,"",String(""),_("input mode")); m_proplist.push_back(p); for(unsigned int i = 0;i < preeditors.size();i ++) { p = Property(String(HONOKA_PROP_INPUTMODE) + String("/") + preeditors[i]->getName(), preeditors[i]->getPropertyName(),String(""),_("mode status")); m_proplist.push_back(p); } if (prediction) { p = Property(HONOKA_PROP_PREDICTOR,"",String(""),_("predictor")); m_proplist.push_back(p); for(unsigned int i = 0;i < predictors.size();i ++) { p = Property(String(HONOKA_PROP_PREDICTOR) + String("/") + predictors[i]->getName(), predictors[i]->getPropertyName(),String(""),_("mode status")); m_proplist.push_back(p); } } if (changeable_splitter) { p = Property(HONOKA_PROP_SPLITTER,"",String(""),_("splitter")); m_proplist.push_back(p); p = Property(String(HONOKA_PROP_SPLITTER) + String("/AUTO"), _("Auto"),String(""),_("mode status")); m_proplist.push_back(p); for(unsigned int i = 0;i < convertors.size();i ++) { p = Property(String(HONOKA_PROP_SPLITTER) + String("/") + convertors[i]->getName(), convertors[i]->getPropertyName(),String(""),_("mode status")); m_proplist.push_back(p); } } p = Property(HONOKA_PROP_CONVERTOR,"",String(""),_("convertor")); m_proplist.push_back(p); for(unsigned int i = 0;i < convertors.size();i ++) { p = Property(String(HONOKA_PROP_CONVERTOR) + String("/") + convertors[i]->getName(), convertors[i]->getPropertyName(),String(""),_("mode status")); m_proplist.push_back(p); } p = Property(HONOKA_PROP_MODESTATUS,"",String(""),_("mode status")); m_proplist.push_back(p); p = Property(HONOKA_PROP_CONVERSIONMODE,"",String(""),_("conversion mode")); m_proplist.push_back(p); } PropertyList::iterator it; it = find(m_proplist.begin(),m_proplist.end(),HONOKA_PROP_INPUTMODE); if (it != m_proplist.end()) { it->set_label(m_preeditor->getPropertyName() + String(" ")); } update_property(*it); if (prediction) { it = find(m_proplist.begin(),m_proplist.end(),HONOKA_PROP_PREDICTOR); if (it != m_proplist.end()) { it->set_label(m_predictor->getPropertyName() + String(" ")); } update_property(*it); } if (changeable_splitter) { it = find(m_proplist.begin(),m_proplist.end(),HONOKA_PROP_SPLITTER); if (it != m_proplist.end()) { if (m_splitter == 0) it->set_label(_("Auto") + String(" ")); else it->set_label(m_splitter->getPropertyName() + String(" ")); } } it = find(m_proplist.begin(),m_proplist.end(),HONOKA_PROP_CONVERTOR); if (it != m_proplist.end()) { it->set_label(m_convertor->getPropertyName() + String(" ")); } update_property(*it); it = find(m_proplist.begin(),m_proplist.end(),HONOKA_PROP_MODESTATUS); if (it != m_proplist.end()) { if (m_conversion) it->set_label(_("Kanji") + String(" ")); else if (m_prediction) it->set_label(_("Yosoku") + String(" ")); else it->set_label(m_preeditor->getModeName() + String(" ")); } update_property(*it); it = find(m_proplist.begin(),m_proplist.end(),HONOKA_PROP_CONVERSIONMODE); if (it != m_proplist.end()) { if (auto_conversion) it->set_label(_("AUTO") + String(" ")); else it->set_label(_("REN") + String(" ")); } update_property(*it); register_properties(m_proplist); } /*! \fn HonokaInstance::updatePreEditor() */ void HonokaInstance::updatePreEditor() { // PreEditorを更新するメソッド。 // 頻繁に呼ばれます。 if (PreEditor::getCommitString().length()) { commit_string(PreEditor::getCommitString()); PreEditor::resetCommitString(); } if (m_preeditor->getTextLength()) { if (auto_conversion && (m_preeditor->getTextLength() == m_preeditor->getPos())) autoConversion(); else { show_preedit_string(); update_preedit_string(m_preeditor->getText(),m_preeditor->getAttributeList()); update_preedit_caret(m_preeditor->getPos()); } // Prediction if ((!m_conversion) && realtime_prediction && prediction && m_predictor->isConnected() && (!auto_conversion)) { if ((predictionDelay > 0) && (preeditCache != m_preeditor->getText())) { m_lookup_table.clear(); m_lookup = false; preeditKeyDelay = HonokaTimer::self()->appendDelayEvent(predictionDelay); hide_lookup_table(); } else { if (preeditCache != m_preeditor->getText()) { m_convList = m_predictor->getPredictionList(m_preeditor->getText()); m_convList.Yomi = 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).kanji); } startLookup(); } else { //m_lookup_table.clear(); hide_lookup_table(); } } } } else hide_lookup_table(); } else { hide_preedit_string(); hide_lookup_table(); } // mini_status用コード。怪しい。 if (mini_status) { update_aux_string(utf8_mbstowcs(m_preeditor->getModeName())); show_aux_string(); } else { hide_aux_string(); } preeditCache = m_preeditor->getText(); updateProperty(); } /*! \fn HonokaInstance::updateConversion() */ void HonokaInstance::updateConversion() { // 変換時の表示更新。 updateConvertedString(); if (m_lookup) { m_lookup_table.set_cursor_pos(m_convList.pos); update_lookup_table(m_lookup_table); update_aux_string(m_convList.Title + getPosPerCount(m_convList.pos,m_convList.count())); show_aux_string(); show_lookup_table(); } else { hide_lookup_table(); hide_aux_string(); } updateProperty(); } void HonokaInstance::process_helper_event (const String &helper_uuid, const Transaction &trans) { WideString t = m_preeditor->getText(); if (helper_uuid == HONOKA_TIMER_UUID) { vector<int> e = HonokaTimer::self()->eventFilter(trans); for(unsigned int i = 0;i < e.size();i ++) { timerEvent(e[i]); } } if ((!m_conversion) && (!m_prediction) && (t != m_preeditor->getText())) updatePreEditor(); } bool HonokaInstance::process_key_event (const KeyEvent& key) { // debug /* String s; scim_key_to_string(s,key); update_aux_string(utf8_mbstowcs(String(key.is_key_release() ? String("R:") : String("P:")) + s)); show_aux_string(); return true; */ // キーイベント処理。 //if (key.is_key_release()) return false; /* trans.clear(); trans.put_command(SCIM_TRANS_CMD_REQUEST); trans.put_command(SCIM_TRANS_CMD_PROCESS_KEY_EVENT); trans.put_data(key); send_helper_event("e135e0ee-5588-423e-a027-f07d769c12a3",trans); */ 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_prediction) return process_prediction_key_event(ke); else return process_preedit_key_event(ke) ; } /*! \fn HonokaInstance::process_preedit_key_event(const KeyEvent &key) */ bool HonokaInstance::process_preedit_key_event(const KeyEvent &key) { if (k_allreset.comp(key)) { unload(); loadPlugins(); init(); m_proplist.clear(); updateProperty(); updatePreEditor(); return true; } if (!m_preeditor->getTextLength()) pStringType = NORMAL; // PreEdit時のキーイベント。 // PreEditorのキーイベントフック。 if (m_preeditor->keyEventHook(key)) { updatePreEditor(); return true; } // フックでfalseかつCommitStringセット時のみ特殊動作。 if (PreEditor::getCommitString().length()) { updatePreEditor(); return false; } // !! ここでreleaseを除去。 if (key.is_key_release()) return false; // 切り替えキー。 for(unsigned int i = 0;i < k_preeditor.size();i ++) { if (k_preeditor[i].comp(key)) { // 同じキーに2種設定があればトグルになると良いと思う。 if (preeditors[i] != m_preeditor) { changePreEditor(preeditors[i]->getName()); updatePreEditor(); return true; } } } for(unsigned int i = 0;i < k_convertor.size();i ++) { if (k_convertor[i].comp(key)) { if (convertors[i] == m_convertor) return true; changeConvertor(convertors[i]->getName()); updatePreEditor(); return true; } } for(unsigned int i = 0;i < k_predictor.size();i ++) { if (k_predictor[i].comp(key)) { if (predictors[i] == m_predictor) return true; //m_predictor = predictors[i]; changePredictor(predictors[i]->getName()); updatePreEditor(); return true; } } // 処理。 if (k_reconversion.comp(key)) { WideString w; int c; if (get_surrounding_text(w,c)) { if (w.length()) { // delete_surrounding_text()を使っての削除とかいるね。 delete_surrounding_text(0 - w.length(),w.length()); startConversion(w); alp_count ++; return true; } } } // バッファが空では無い場合。 if (m_preeditor->getTextLength()) { if (k_conversion_start.comp(key)) { startConversion(m_preeditor->getText(true)); alp_count ++; return true; } else if (k_multi_conversion.comp(key)) { startConversion(m_preeditor->getText(true),true); alp_count ++; return true; } else if (k_commit.comp(key)) { if (auto_conversion) { commit_string(getConvertedText()); if (prediction) if (m_predictor->isConnected()) m_predictor->update(getConvertedText(),m_preeditor->getText(true)); m_convertor->reset(); } else { commit_string(m_preeditor->getText(true)); if (prediction) if (m_predictor->isConnected()) m_predictor->update(m_preeditor->getText(true),m_preeditor->getText(true)); } m_preeditor->reset(); while(preeditStack.size()) { preeditStack.pop(); } 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(); if (preeditCache != m_preeditor->getText()) pStringType = NORMAL; updatePreEditor(); return true; } else if (k_convert_ctype.comp(key)) { switch(pStringType) { case NORMAL: { pString = m_preeditor->getText(); pStringType = HIRA; m_preeditor->kataHira(); break; } case HIRA: { m_preeditor->setText(pString); pStringType = KATA; m_preeditor->hiraKata(); break; } case KATA: { m_preeditor->setText(pString); pStringType = HALF; m_preeditor->toHalf(); break; } case HALF: { m_preeditor->setText(pString); pStringType = WIDE; m_preeditor->toWide(); break; } case WIDE: { m_preeditor->setText(pString); pStringType = HIRA; m_preeditor->kataHira(); break; } default: { break; } } updatePreEditor(); return true; } 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_prediction.comp(key) && prediction) { if ((!realtime_prediction) && m_predictor->isConnected()) { m_convList = m_predictor->getPredictionList(m_preeditor->getText()); m_convList.Yomi = 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).kanji); } startLookup(); } } if ((m_convList.kType == PREDICTION) && (m_convList.count()) && (m_convList.Yomi == m_preeditor->getText())) { return process_prediction_key_event(key); } } else // 数字キーによる直接予測選択。甘いか?。 if (numkeyselect && realtime_prediction && prediction && select_prediction_direct) { if ((m_convList.kType == PREDICTION) && (m_convList.count()) && (m_convList.Yomi == m_preeditor->getText())) { for(unsigned int i = 0;i < 10;i ++) { if (k_selection[i].comp(key)) { int numc = i - 1; if (numc < 0) numc = 9; if (m_convList.count() > numc) { m_convList.pos = numc; commit_string(m_convList.kouho.at(m_convList.pos).kanji); m_preeditor->reset(); updatePreEditor(); return true; } } } } } } // バッファの存在にかかわらず。 if (k_cancel.comp(key)) { if (m_preeditor->cancelEvent()) { updatePreEditor(); return true; } if (preeditStack.size()) { m_preeditor->reset(); m_preeditor->setText(preeditStack.top()); m_preeditor->setPos(preeditStack.top().length()); preeditStack.pop(); } else if (m_preeditor->getTextLength()) { m_preeditor->reset(); } updatePreEditor(); return true; } if (k_next_convertor.comp(key) || k_prev_convertor.comp(key)) { for(unsigned int i = 0;i < convertors.size();i ++) { if (convertors[i]->getName() == m_convertor->getName()) { if (k_next_convertor.comp(key)) { if (i == (convertors.size() - 1)) i = 0; else i ++; } else { if (i == 0) i = convertors.size() - 1; else i --; } changeConvertor(convertors[i]->getName()); 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)) { if (preeditCache != m_preeditor->getText()) pStringType = NORMAL; updatePreEditor(); return true; } else { // preeditorで処理できなかった場合はやはりcommitしてアプリケーションに返すべきだ。 if (m_preeditor->getTextLength()) { if (auto_conversion) { commit_string(getConvertedText()); m_convertor->reset(); } else commit_string(m_preeditor->getText(true)); } m_preeditor->reset(); updatePreEditor(); } if (PreEditor::getCommitString().length()) updatePreEditor(); return false; } /*! \fn HonokaInstance::process_conversion_key_event(const KeyEvent &key) */ bool HonokaInstance::process_conversion_key_event(const KeyEvent &key) { preeditCache.clear(); // 変換時のキーイベント処理。 // 喰う!。 if (key.is_key_release()) return true; if (PreEditor::isThrough(key)) 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_furigana_commit.comp(key)) { WideString cm; for(unsigned int i = 0;i < segments.size();i ++) { if (segments[i].getKanji() == segments[i].getYomi()) { cm += segments[i].getKanji(); } else { for(unsigned int j = 0;segments[i].getYomi().length() - j != 0;j ++) { if (segments[i].getKanji()[segments[i].getKanji().length() - j - 1] != segments[i].getYomi()[segments[i].getYomi().length() - j - 1]) { cm += segments[i].getKanji().substr(0,segments[i].getKanji().length() - j); cm += utf8_mbstowcs(String("(")); cm += segments[i].getYomi().substr(0,segments[i].getYomi().length() - j); cm += utf8_mbstowcs(String(")")); cm += segments[i].getKanji().substr(segments[i].getKanji().length() - j,segments[i].getKanji().length()); break; } } } } commit_string(cm); m_convertor->updateFrequency(); if (prediction) if (m_predictor->isConnected()) m_predictor->update(getConvertedText(),m_preeditor->getText(true)); m_preeditor->reset(); m_convertor->reset(); m_conversion = false; updatePreEditor(); m_lookup = false; alp_count = 1; if (m_def_convertor != m_convertor) m_convertor = m_def_convertor; updateProperty(); return true; } else // 確定キー if (k_commit.comp(key)) { commit_string(getConvertedText()); m_convertor->updateFrequency(); if (prediction) if (m_predictor->isConnected()) m_predictor->update(getConvertedText(),m_preeditor->getText(true)); m_preeditor->reset(); m_convertor->reset(); m_conversion = false; updatePreEditor(); m_lookup = false; alp_count = 1; if (m_def_convertor != m_convertor) m_convertor = m_def_convertor; updateProperty(); return true; } else // 結果をPreEditorに戻すキー。 if (k_result_to_preedit.comp(key)) { preeditStack.push(m_preeditor->getText(true)); m_preeditor->reset(); m_preeditor->setText(getConvertedText()); m_preeditor->setPos(getConvertedText().length()); m_convertor->updateFrequency(); m_convertor->reset(); m_conversion = false; m_lookup = false; alp_count = 1; if (m_def_convertor != m_convertor) m_convertor = m_def_convertor; updateProperty(); updatePreEditor(); return true; } else // キャンセルキー。 if (k_cancel.comp(key) || k_backspace.comp(key)) { m_convertor->reset(); m_conversion = false; m_lookup = false; alp_count = 0; if (m_def_convertor != m_convertor) m_convertor = m_def_convertor; updateProperty(); 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 ++; if (!m_no_update) m_convertor->select(m_convList.pos); updateConversion(); return true; } else // 注目文節拡縮キー。 if (k_conversion_expand.comp(key) || k_conversion_shrink.comp(key)) { m_no_update = false; bool r; k_conversion_shrink.comp(key) ? r = m_convertor->resizeRegion(-1) : r = m_convertor->resizeRegion(1); if (!r) return true; m_convList = m_convertor->getResultList(); if (alp == -1) { startLookup(); } else m_lookup = false; updateConversion(); alp_count = 1; return true; } else // 連想変換(特殊1)キー if (k_conversion_rensou.comp(key)) { m_no_update = false; m_convList = m_convertor->getResultList(m_convertor->getPos(),SPECIAL1); if (m_convList.count() == 0) return true; startLookup(); updateConversion(); alp_count = 1; return true; } else // 異形字変換(特殊2)キー。 if (k_conversion_ikeiji.comp(key)) { m_no_update = false; m_convList = m_convertor->getResultList(m_convertor->getPos(),SPECIAL2); 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)) { m_no_update = false; k_conversion_backward.comp(key) ? m_convertor->setPos(m_convertor->getPos() - 1) : m_convertor->setPos(m_convertor->getPos() + 1); m_convList = m_convertor->getResultList(); 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; if (k_convert_hiragana.comp(key) && k_convert_katakana.comp(key)) { PreEditor::convKataHira(res); if (res == m_convList.kouho[m_convList.pos].kanji) PreEditor::convHiraKata(res); } else 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].kanji) { m_convList.pos = i; if (!m_no_update) m_convertor->select(m_convList.pos); updateConversion(); break; } } return true; } else // 文字種トグルキー if (k_convert_ctype.comp(key)) { // m_no_updateをチェックし、文字種リストをでっちあげる。 // 文節毎のエンジン切り替え時は働かない。 if (m_no_update) { m_convList.pos ++; if (m_convList.pos >= m_convList.count()) m_convList.pos = 0; updateConversion(); return true; } m_no_update = true; pString = m_convList.Yomi; WideString t; int dp; m_convList.kouho.clear(); t = pString; PreEditor::convKataHira(t); m_convList.kouho.push_back(ResultEntry(t)); t = pString; PreEditor::convHiraKata(t); m_convList.kouho.push_back(ResultEntry(t)); t = pString; PreEditor::convZenHan(t,dp); m_convList.kouho.push_back(ResultEntry(t)); t = pString; PreEditor::convHanZen(t,dp); m_convList.kouho.push_back(ResultEntry(t)); m_lookup = false; updateConversion(); return true; } else // 次/前変換エンジン切り替えキー。 if ((k_next_convertor.comp(key) || k_prev_convertor.comp(key)) && (m_convertor != m_multi)) { for(unsigned int i = 0;i < convertors.size();i ++) { if (convertors[i]->getName() == m_convertor->getName()) { if (k_next_convertor.comp(key)) { if (i == (convertors.size() - 1)) i = 0; else i ++; } else { if (i == 0) i = convertors.size() - 1; else i --; } changeConvertor(convertors[i]->getName()); if (m_def_convertor != m_convertor) { m_def_convertor->reset(); startConversion(); } return true; } } } else // 数字キーによる候補選択。 if (numkeyselect && m_lookup) { for(unsigned int i = 0;i < 10;i ++) { if (k_selection[i].comp(key)) { int numc = i - 1; if (numc < 0) numc = 9; if (m_lookup_table.get_current_page_size() <= numc) return true; m_convList.pos = numc + m_lookup_table.get_current_page_start(); if (!m_no_update) m_convertor->select(m_convList.pos); m_no_update = false; m_convertor->setPos(m_convertor->getPos() + 1); m_convList = m_convertor->getResultList(); updateConversion(); startLookup(); return true; } } } // 注目文節の候補を別変換エンジンから取得するキー。 if (m_convertor != m_multi) { for(unsigned int i = 0;i < k_convertor.size();i ++) { if (k_convertor[i].comp(key)) { if (convertors[i] == m_convertor) return true; if (!convertors[i]->isConnected()) if (!convertors[i]->connect()) return true; WideString y; for(unsigned int j = 0;j < segments.size();j ++) y += segments[j].getYomi(); convertors[i]->setYomiText(y); //convertors[i]->setYomiText(m_preeditor->getText(true)); if (convertors[i]->ren_conversion() <= 0) return true; m_no_update = true; MultiConvertor::aline(m_convertor,convertors[i]); m_convList = convertors[i]->getResultList(m_convertor->getPos()); m_convList.Title = utf8_mbstowcs(String("(") + convertors[i]->getPropertyName() + String(")")); convertors[i]->reset(); startLookup(); updateConversion(); return true; } } } // それ以外のキーの場合、表示可能キーなら確定してPreEdit入力を再開。 if (key.get_unicode_code()) { commit_string(getConvertedText()); m_convertor->updateFrequency(); if (prediction) if (m_predictor->isConnected()) m_predictor->update(getConvertedText(),m_preeditor->getText(true)); m_preeditor->reset(); m_convertor->reset(); m_conversion = false; m_lookup = false; alp_count = 0; if (m_def_convertor != m_convertor) m_convertor = m_def_convertor; updateProperty(); updatePreEditor(); return process_preedit_key_event(key); } return true; } /*! \fn HonokaInstance::process_prediction_key_event(const KeyEvent &key) */ bool HonokaInstance::process_prediction_key_event(const KeyEvent &key) { preeditCache.clear(); // 予測選択時のキーイベント処理。 if (key.is_key_release()) return true; if (!m_prediction) { m_prediction = true; update_aux_string(m_convList.Title + getPosPerCount(m_convList.pos,m_convList.count())); show_aux_string(); update_preedit_string(m_convList.kouho.at(m_convList.pos).kanji); update_preedit_caret(m_predictor->getPos()); 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_prediction.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_aux_string(m_convList.Title + getPosPerCount(m_convList.pos,m_convList.count())); show_aux_string(); update_lookup_table(m_lookup_table); update_preedit_string(m_convList.kouho.at(m_convList.pos).kanji); update_preedit_caret(m_predictor->getPos()); updateProperty(); return true; } else if (k_commit.comp(key)) { m_prediction = false; commit_string(m_convList.kouho.at(m_convList.pos).kanji); m_preeditor->reset(); updatePreEditor(); return true; } else if (k_cancel.comp(key) || k_backspace.comp(key)) { m_prediction = false; updatePreEditor(); return true; } if (numkeyselect) { for(unsigned int i = 0;i < 10;i ++) { if (k_selection[i].comp(key)) { int numc = i - 1; if (numc < 0) numc = 9; if (m_lookup_table.get_current_page_size() <= numc) return true; //select_candidate((unsigned int)numc); m_convList.pos = numc + m_lookup_table.get_current_page_start(); m_prediction = false; commit_string(m_convList.kouho.at(m_convList.pos).kanji); m_preeditor->reset(); updatePreEditor(); return true; } } } if (!key.get_unicode_code()) return true; m_prediction = false; commit_string(m_convList.kouho.at(m_convList.pos).kanji); m_preeditor->reset(); updatePreEditor(); return process_preedit_key_event(key); } void HonokaInstance::move_preedit_caret (unsigned int pos) { //if (!m_conversion) m_preeditor->setPos(pos); //update_preedit_caret(pos); } void HonokaInstance::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; if ((!m_no_update) && (m_conversion)) m_convertor->select(m_convList.pos); if (m_convList.kType != PREDICTION) { updateConvertedString(); } else { update_preedit_string(m_convList.kouho.at(m_convList.pos).kanji); update_preedit_caret(0); if (!m_prediction) { // マウスで選択した場合は予測選択モードに突入。 m_prediction = true; show_preedit_string(); updateProperty(); } } m_lookup_table.set_cursor_pos(m_convList.pos); update_aux_string(m_convList.Title + getPosPerCount(m_convList.pos,m_convList.count())); show_aux_string(); update_lookup_table(m_lookup_table); } void HonokaInstance::update_lookup_table_page_size (unsigned int page_size) { m_lookup_table.set_page_size (page_size); } void HonokaInstance::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; if ((!m_no_update) && (m_conversion)) m_convertor->select(m_convList.pos); if (m_conversion) updateConvertedString(); if (m_prediction) { update_preedit_string(m_convList.kouho[m_convList.pos].kanji); update_preedit_caret(0); } m_lookup_table.set_cursor_pos(m_convList.pos); update_aux_string(m_convList.Title + getPosPerCount(m_convList.pos,m_convList.count())); show_aux_string(); update_lookup_table(m_lookup_table); } void HonokaInstance::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; if ((!m_no_update) && (m_conversion)) m_convertor->select(m_convList.pos); if (m_conversion) updateConvertedString(); if (m_prediction) { update_preedit_string(m_convList.kouho[m_convList.pos].kanji); update_preedit_caret(0); } m_lookup_table.set_cursor_pos(m_convList.pos); update_aux_string(m_convList.Title + getPosPerCount(m_convList.pos,m_convList.count())); show_aux_string(); update_lookup_table(m_lookup_table); } void HonokaInstance::reset () { // Qt-immodule+scim-qtimmではこのメソッドが大量に呼ばれるようだが、他ではどうなのか?。 alp_count = 0; m_conversion = false; m_lookup = false; m_convertor->reset(); m_preeditor->reset(); } void HonokaInstance::focus_in () { if (!m_conversion) updatePreEditor(); else updateProperty(); } void HonokaInstance::focus_out () { // フォーカスを失った時は全てコミット!。 if (m_conversion) { commit_string(getConvertedText()); m_convertor->updateFrequency(); if (prediction) if (m_predictor->isConnected()) m_predictor->update(getConvertedText(),m_preeditor->getText(true)); m_convertor->reset(); if (m_def_convertor != m_convertor) m_convertor = m_def_convertor; m_conversion = false; m_lookup = false; alp_count = 0; } else if (m_prediction) { m_prediction = false; commit_string(m_convList.kouho.at(m_convList.pos).kanji); m_preeditor->reset(); }else if (m_preeditor->getTextLength()) { commit_string(m_preeditor->getText(true)); } m_preeditor->reset(); updatePreEditor(); } void HonokaInstance::trigger_property (const String &property) { String s = HONOKA_PROP_INPUTMODE; if ((property.length() > s.length()) && (property.substr(0,s.length()) == s)) { changePreEditor(property.substr(s.length() + 1)); updateProperty(); } s = HONOKA_PROP_PREDICTOR; if ((property.length() > s.length()) && (property.substr(0,s.length()) == s)) { changePredictor(property.substr(s.length() + 1)); updateProperty(); } s = HONOKA_PROP_CONVERTOR; if ((property.length() > s.length()) && (property.substr(0,s.length()) == s)) { changeConvertor(property.substr(s.length() + 1)); if (m_conversion) { if (m_def_convertor != m_convertor) { m_def_convertor->reset(); startConversion(); } } updateProperty(); } s = HONOKA_PROP_SPLITTER; if ((property.length() > s.length()) && (property.substr(0,s.length()) == s)) { changeSplitter(property.substr(s.length() + 1)); updateProperty(); } s = HONOKA_PROP_CONVERSIONMODE; if (property == s) { auto_conversion ? auto_conversion = false : auto_conversion = true; updatePreEditor(); } } /*! \fn HonokaInstance::startConversion(WideString s,bool multi) */ void HonokaInstance::startConversion(WideString s,bool multi) { // 変換開始処理。 // 一度lookupは消しておこう。 m_def_convertor = m_convertor; if (multi) m_convertor = m_multi; if (!s.length()) s = yomi; else yomi = s; vector<Segment> spsegs; m_lookup = false; m_lookup_table.clear(); hide_lookup_table(); hide_aux_string(); if (m_splitter && (m_splitter != m_convertor) && (!multi)) { m_convertor->unSelected(); m_splitter->selected(); if (!m_splitter->isConnected()) { if (!m_splitter->connect()) { m_splitter->unSelected(); update_aux_string(utf8_mbstowcs(String(_("could not connect to server.")))); show_aux_string(); return; } } m_splitter->setYomiText(s); if (m_splitter->ren_conversion() <= 0) { update_aux_string(utf8_mbstowcs(String(_("The error was received from Converter. ")))); show_aux_string(); return; } spsegs = m_splitter->getSegmentList(); m_splitter->reset(); m_splitter->unSelected(); m_convertor->selected(); s.clear(); for(unsigned int i = 0;i < spsegs.size();i ++) s += spsegs[i].getYomi(); } if (!m_convertor->isConnected()) { if (!m_convertor->connect()) { update_aux_string(utf8_mbstowcs(String(_("could not connect to server.")))); show_aux_string(); m_convertor = m_def_convertor; return; } } m_convertor->setYomiText(s); if (m_convertor->ren_conversion() <= 0) { update_aux_string(utf8_mbstowcs(String(_("The error was received from Converter. ")))); show_aux_string(); m_convertor = m_def_convertor; return; } if (m_splitter && (m_splitter != m_convertor) && (!multi)) { // aline for(unsigned int i = 0;i < spsegs.size();i ++) { int bl = spsegs[i].getYomi().length(); int cl = m_convertor->getResultList(i).Yomi.length(); if (bl != cl) { bool t = m_convertor->resizeRegion(bl - cl); if (!t) { update_aux_string(utf8_mbstowcs(String(_("The error was received from Converter. ")))); m_convertor->reset(); show_aux_string(); return; } } } } m_no_update = false; m_convList.kouho.clear(); m_convList = m_convertor->getResultList(); m_conversion = true; segments = m_convertor->getSegmentList(); alp_count = 1; show_preedit_string(); updateConvertedString(); if (alp == -1) { startLookup(); } updateProperty(); } /*! \fn HonokaInstance::autoConversion() */ void HonokaInstance::autoConversion() { // 自動変換処理コード。 if (!m_convertor->isConnected()) { if (!m_convertor->connect()) { update_aux_string(utf8_mbstowcs(String(_("could not connect to server.")))); show_aux_string(); show_preedit_string(); update_preedit_string(m_preeditor->getText(),m_preeditor->getAttributeList()); update_preedit_caret(m_preeditor->getPos()); return; } } m_convertor->reset(); m_convertor->setYomiText(m_preeditor->getText(true)); if (m_convertor->ren_conversion() <= 0) { update_aux_string(utf8_mbstowcs(String(_("could not connect to server.")))); show_aux_string(); show_preedit_string(); update_preedit_string(m_preeditor->getText(),m_preeditor->getAttributeList()); update_preedit_caret(m_preeditor->getPos()); return; } segments = m_convertor->getSegmentList(); WideString t; for(unsigned int i = 0;i < segments.size();i ++) t += segments[i].getKanji(); show_preedit_string(); update_preedit_string(t); update_preedit_caret(t.length()); } /*! \fn HonokaInstance::createLookupTable(ResultList cList) */ void HonokaInstance::createLookupTable(ResultList cList) { // 候補一覧を作る。 hide_lookup_table(); m_lookup_table.clear(); if (!cList.count()) return; for (unsigned int i = 0;i < cList.count();i ++) { if (cList.kouho.at(i).label.length()) m_lookup_table.append_candidate(cList.kouho.at(i).label); else m_lookup_table.append_candidate(cList.kouho.at(i).kanji); } m_lookup_table.set_cursor_pos(cList.pos); update_aux_string(cList.Title + getPosPerCount(cList.pos,cList.count())); show_aux_string(); update_lookup_table(m_lookup_table); } /*! \fn HonokaInstance::startLookup() */ void HonokaInstance::startLookup() { // 候補一覧を表示する。 createLookupTable(m_convList); if (m_convList.count() == 0) { m_lookup = false; return; } m_lookup = true; update_aux_string(m_convList.Title + getPosPerCount(m_convList.pos,m_convList.count())); show_aux_string(); show_lookup_table(); } /*! \fn HonokaInstance::getPosPerCount(int p,int c) */ WideString HonokaInstance::getPosPerCount(int p,int c) { char data[256]; sprintf(data," [%d/%d]",p + 1,c); return utf8_mbstowcs(String(data)); } /*! \fn HonokaInstance::timerEvent(int id) */ void HonokaInstance::timerEvent(int id) { for(unsigned int i = 0;i < preeditors.size();i ++) { if (preeditors[i]->findTimerEventId(id)) { preeditors[i]->timerEvent(id); //if ((!m_conversion) && (!m_prediction)) updatePreEditor(); return; } } for(unsigned int i = 0;i < convertors.size();i ++) { if (convertors[i]->findTimerEventId(id)) { convertors[i]->timerEvent(id); return; } } for(unsigned int i = 0;i < predictors.size();i ++) { if (predictors[i]->findTimerEventId(id)) { predictors[i]->timerEvent(id); return; } } if ((id == preeditKeyDelay) && (!m_conversion) && (!m_prediction)) { WideString w = m_preeditor->getText(); if (!w.length()) { hide_lookup_table(); return; } m_convList = m_predictor->getPredictionList(w); m_convList.Yomi = w; 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).kanji); } if (w == m_preeditor->getText()) { startLookup(); hide_aux_string(); } else hide_lookup_table(); } else { //m_lookup_table.clear(); hide_lookup_table(); } } }