/***************************************************************************
* 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);
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 (1) 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 (1) {
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 (1) {
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();
}
}
}