Mar 06

Beta 2中更新的内容:

  1. 修正了一个导致crash的bug (#36)
  2. 修正了无法安装到~/Library/Input\ Methods的bug (#30)
  3. 加入了在切换中英文时提交的选项 (#18)
  4. 加入了中文的本地化界面
  5. 将全角半角切换快捷键从Shift+Space改为Alt+Space,避免和Safari的向上翻页键冲突
  6. 提供了安装包,同时支持Mac OS 10.5和10.6,并支持PowerPC系统 (未验证)
  7. 将升级检测和数据文件校验等配置文件迁移到sunpinyin.googlecode.com

欢迎下载试用,SunPinyin-MacOS-2.0.zip。已安装beta 1版本的朋友,无需删除已安装的版本,直接运行安装程序即可。首次安装的朋友请注意,当安装程序进行到“下载数据文件”步骤时,请点击“开始…”按钮下载必要的数据文件(文件较大,可能比较耗时)。

Tagged with:
Feb 26


(由左到右,分别是我,江疆,薛伟和柴可夫)

柴可夫是SunPinyin项目的主力开发人员之一。这次来京,终于有机会一聚,得以一见Kov同学的真容,让人相见恨晚啊。席间大家相谈甚欢,也讨论了SunPinyin下一步的开发规划,希望我们新的一年做得更好 … 同时也期待Mike同学回国一聚 :)

Tagged with:
Nov 23

首先要说明的是,sunpinyin-2.0 for Mac版本还在开发中,目前的状况是,可以build并安装到系统中,并且能够进行输入,不过用户配置方面(从界面到代码)都还没有实现。

第一步,需要安装分布式版本管理工具mercurial,并安装MacPorts,以安装必要的autotools软件包:

$ sudo /opt/local/bin/port install glib2 intltool sqlite3
$ export PATH=$PATH:/Developer/usr/bin:/opt/local/bin
(为了将来方便,可将此行加入到~/.bash_profile中)

接下来,从OpenSolaris上check out项目的代码,这个会花费比较长的时间,需要耐心 :)

$ hg clone ssh://anon@hg.opensolaris.org/hg/nv-g11n/inputmethod

然后进入到sunpinyin2目录中,执行autogen.sh

$ cd sunpinyin2
$ cd data; ln -s ../../sunpinyin/ime/data/lm_sc.t3g.le lm_sc.t3g; cd -
$ ACLOCAL_FLAGS=-I/opt/local/share/aclocal ./autogen.sh \
  --disable-cle --disable-ibus

由于目前在autogen.sh里,hardcoded了--enable-ibus等选项,所以在执行configure时会出错,所以需要再用适当的选项重新执行一遍configure;另外需要使用MacPorts的glibtoolize重新生成一下libtool,否则无法进行链接,

$ /opt/local/bin/glibtoolize --force --copy
$ ./configure --enable-debug --disable-cle --disable-ibus

接下来需要build词表,

$ cd build; make genpyt; make lexicon; cd -

最后就是build基于IMKit的输入法前端了,

$ cd wrapper/macos
$ make clean; make
$ sudo make install

现在,sunpinyin-2.0应该已经安装到系统中了,需要re-login才可以看到这个输入法。

调试的时候,需要用ssh从另外一台机器远程登录到本机上。之后,如果要验证bug fixes,为了避免重复re-login,可以反复执行killall -9 SunPinyin,直至系统报告没有SunPinyin进程,然后也要重新启动用来测试的应用(例如textedit)。

Tagged with:
Nov 10

ibus-sunpinyin 2.0 发布 RC2,详情请参见http://groups.google.com/group/sunpinyin-developers/… 另外,linuxtoy发了一篇关于如何在fedora上安装ibus-sunpinyin的文档,希望有朋友能帮忙build一个rpm包,我们可以放到google-group讨论组、以及项目网站上,方便大家下载安装。

总体的状况是,ibus-sunpinyin2的发展形势很喜人啊 :)

Tagged with:
Nov 08

从朋友那里得知,ibus-sunpinyin2已经进入gentoo官方库,感谢整个开发团队(特别是Kov),以及所有支持和关心我们的朋友们!:)

Tagged with:
Nov 04

感谢Kov Chai的超辛苦付出,以及William XueLeo Zheng等同学们的共同努力,ibus-sunpinyin 2.0发布了第一个release candidate!详情请参见:

http://groups.google.com/group/sunpinyin-developers/…

Tagged with:
Sep 12

我们刚刚为SunPinyin项目建立了一个google-group。虽然oso-inputmethod项目也有一个mail-list,不过是和其他opensolaris i18n/l10n项目share的。而且似乎国内的开发者或用户,还是更习惯和倾向使用google-group作为交流的途径。因此我们就创建了这个group。

SunPinyin的开发者会使用这个mail group来讨论开发相关的问题,同时用户也可以用这个mail group来报告发现的问题。(觉得再建一个sunpinyin-users的group还不是这么紧迫和必要。)大家也可以直接发邮件到sunpinyin-developers@googlegroups.com

期待您的加入!

Tagged with:
Sep 07

sunpinyin_event_flow

顺便再补充一句,为了将来能让ime-core编译为一个shared object,SunPinyin2开始使用自己的key mapping。这个文件列出了一些特殊键(function key),它们的keycode和X11 keysym是一致的,因此和scim和ibus的keysym也是一致的。其他的键,例如a-z/A-Z/0-9等和ASCII兼容的,可以直接传入(其实这和X11的keysym还是一致的)。再以外的keycode就不处理直接返回了。因此各位在给SunPinyin2做porting时,还需要编写一个简单的键盘事件的影射。

Tagged with:
Sep 06

SunPinyin2在设计和实现的过程中,希望能同时支持简体、繁体的词典及语言模型,支持不同的拼音方案,支持不同的输入风格(包括微软拼音和类似sogou或google拼音)。不同的输入风格,对应了不同的view的实现。(虽然目前SunPinyin2还没有重新实现微软拼音的输入风格——CIMIModernView。)

这些选项组合起来数目繁多,不过它们都是正交的,正好可以让我们使用policy based的实现方式。

我们定义了一个CSunpinyinProfile的模板类,它继承了ISunpinyinProfile这个公共接口类(否则我无法声明一个保存其指针的container),和它的三个模板参数,LanguagePolicy,PinyinSchemePolicy,InputStylePolicy。它的createProfile方法,调用policy类中的相关方法,来创建具体的一个view实例。为了避免创建policy的实例,并且更重要的是要共享policy的公共数据,policy类都是单件(singleton)。

LanguagePolicy负责初始化词典、用户词典和语言模型,以及根据这些资源创建CIMIContext类的实例。CSimplifiedChinesePolicy是一个具体的实现。另外还有一些方法,可以让你设置CIMIContext类实例的缺省属性。例如,enableFullPunctenableFullSymbolsetPunctMapping方法设置s_getFullPunctOp(被所有由该policy类创建的CIMIContext实例所共享)的标点符号影射。我们之前总结为shared & global的用户配置项。可以设想,用户在设置对话框自行定义标点符号的映射关系后,程序员只需要调用CSimplifiedChinesePolicy::setPunctMapping。这个配置项的更改会应用到所有现有的输入上下文(或会话),对输入上下文来说是透明的。

PinyinSchemePolicy负责创建拼音切分器的实例。CQuanpinSchemePolicyCShuangpinSchemePolicy是两个具体的实现。以CQuanpinSchemePolicy类为例,createPySegmentor方法创建了CQuanpinSegmentor的一个实例并返回。和CSimplifiedChinesePolicy类似,CQuanpinSchemePolicy也有一些shared & global的配置项,例如是否支持易混淆音和自动纠错。

InputStylePolicy负责创建CIMIView的实例。CClassicStylePolicy是一个具体的实现。它只是简单的创建一个CIMIClassicView的实例并返回。CSunPinyinProfile<…>::createProfile方法虽然也是返回一个view的实例,不过这个view是已经设置停当、可以工作的view。

CSunpinyinSessionFactory是一个singleton的工厂类,其createSession方法根据factory中policy的设定,调用某个CSunpinyinProfile实例的createProfile方法,创建一个具体的view。要添加新的语言支持或拼音方案,不仅要完成自己的那部分coding,还要记得编写相应的policy classes,并将支持的所有组合注册到CSunpinyinSessionFactory中(没办法,在这个地方就只能穷举了)。

因为我们最后expose给外部的是一个view的实例,所以如果用户的配置涉及到对policy的切换(我们之前总结为non-shared but global的配置项),以前创建的输入上下文(即view),就面临一个抉择。要么保持不变,继续使用其目前的输入风格;要么要重新创建,discard掉以前上下文的状态信息(例如preedit/candidates)。通常,我们对某个平台的移植,都是创建一个包含view的会话类,这个会话类适配该平台的接口,并将输入事件filter给view。那么我们的这些会话类是如何知道发生了non-shared but global选项的改变呢?

CSunpinyinSessionFactory类提供了一个简单的方法,updateToken/getToken。当平台相关的会话类调用CSunpinyinSessionFactory类创建一个view的实例,同时应该调用getToken得到一个token(口令)。当会话类得到焦点的时候,它可以调用getToken再次得到一个token,比较与自己持有的这个token是否一致。如果不一致,就表明发生了non-shared but global选项的更改。与此相对应地,如果用户对non-shared but global的选项发生了修改,程序员应该要调用updateToken去更新factory当前的token。

这个方式有些丑陋,稍微改观一点的方法可能是,我们再加入一个抽象层次,例如CSunpinyinSession,然后它用signal/slot的方式connect到factory的reset_session信号。另一个问题,配置项还是比较分散,如果要编写一个集中的CSunpinyinOption类的话,就会有很多duplicated的代码。我对上面这些问题,还没有想得很清楚,也非常欢迎大家多提宝贵意见!:)

行文至此,我的“What’s new in SunPinyin2”系列也就暂时告一段落了。希望对William、以及SunPinyin2的移植工作有所帮助。我还会继续竭尽全力,投入到SunPinyin2的开发和移植工作中 :)

Tagged with:
Sep 05

原先的SunPinyin没有用户词典,只是通过User History Cache纪录了用户近期输入的bi-gram信息。如果一个bi-gram,其概率比系统词典的某个uni-gram要低,这个bi-gram的组合就不会出现在用户的候选列表中。例如,虽然用户频繁的输入钥匙,但是它依然很难出现在候选列表中,因为“要是”这个unigram的概率要更高。如果“钥匙”出现在候选中,一定是第一候选,因为它是作为一个最佳候选句子来呈现给用户的。如果用户选择了“要是”,那么“钥匙”又不知道要过多久才能出现了。这个缺陷也是广受大家诟病的地方。其实,SunPinyin原先的架构是支持将用户自定义词放到lattice上进行搜索的

我们在SunPinyin2中,通过sqlite3来实现用户词典,目前我们的用户词典支持记录<=6个的字符。

CUserDict::_createTable/_createIndexes:

这两个私有方法尝试创建一个table和index。这个表的结构是,首先词的ID(从1开始的)和长度,接下来是6个声母,然后是6个韵母,再其次是6个声调。然后我们为长度+6个声母建立了一个索引。sqlite的query对搜索条件和index有一些限制,要求条件的次序和index的次序相同,并且一旦某个条件是非相等性的(例如>),则该条件及其之后的条件都无法用index来加速。另外,每个from子句只能使用一个index。

因为我们经常会有不完整拼音的查询,或者换句话说用户经常会输入不完整拼音,所以table和index就被设计成了这个样子。

CUserDict::addWord (syllables, word):

使用了sqlite中的prepared statement来进行插入。最后,在插入成功的情况下,调用sqlite3_last_insert_rowid得到上一次插入记录的row id,加上一个offset并返回。如果失败,就返回0。

CUserDict::removeWord (wid):

这个相对简单,按照wid将记录从数据库中删除。

CUserDict::getWords (syllables, result):

这个方法将syllables在数据库中对应的记录,放到result中。我们返回的词id类型,和系统词典的保持一致,都是CPinyinTrie::TWordIdInfo。这里再解释一下,用户词典的最大容量为什么是6万多个。这个就是由于CPinyinTrie::TWordIdInfo的m_id的长度决定的,是2^18-1。

我们按照sqlite的限制,小心翼翼地组织好查询的where子句,查询,然后迭代结果,填充results,最后返回。

CUserDict::operator [] (wid):

这个方法也相对简单,就是返回wid对应的字符串。因为sqlite只支持utf8和utf16,而且utf16还要使用一套不同的接口,所以我们还是使用utf8作为数据库内的字符串编码。而sunpinyin-ime要求的是ucs-4编码的字符串,所以还要进行一个编码转换。同时把(wid, wstr)这个pair加入到m_dict中。wstr是动态分配的,由m_dict在析构时释放。这里还利用了这样一个事实,std::basic_string是COW的。我们在m_dict中保存的其实是wstr的拷贝,不过这个拷贝和wstr共享同一个C string的buffer。

接下来,我会介绍SunPinyin2中另一个比较复杂和tricky的部分——用户配置(imi_options.h),这一部分到目前还没有完全定型,非常欢迎大家多提宝贵意见。

Tagged with:
preload preload preload