关于 ibus-sogoupycc 的扩展

本来想把一些示例放在项目的 wiki 页上的,但是我还想说一些其他的闲话,而且目前扩展虽然有一些实用性了,却缺乏执行保护,可以把输入法弄得不稳定,所以这些内容就放到这里好了。如果你只想看看如何使用输入法的扩展,请向下找到 ^_. 表情后从那里开始看。

似乎扩展是很流行的样子,各种浏览器,foobar2000,谷歌拼音,WPS,都可以用扩展。

其中,有的软件成功了,令人爱不释手,比如像 Firefox,foobar2000。有的软件却没有因为扩展成功,比如谷歌拼音。或者说扩展没有给人带来好感,比如 IE 浏览器。

我觉得作为一个支持扩展的软件,最重要的就是扩展要比较有用,可以做一些事情,这一点上谷歌拼音做得就不好,由于扩展而变得比较成功的软件在这方面做得都比较好。其次,扩展要容易开发,再往后,出于安全的考虑,扩展的能力要受到约束。这两点 IE 相比 Firefox 就弱了一些,不过 Firefox 的扩展写起来还是挺麻烦的,比如其中的多国语言化就非常麻烦,对于不同的地方要使用不同的方法,总共有三种。而由于 Firefox 的灵活性,出现了 Mozilla JetpackGreaseMonkey 等,都可以让扩展写起来方便一些。

在很长的一段时间内,我觉得编写软件,技术含量是最重要的, 一个更好的算法可以带来更快的速度,或者更好的结果,当然用户体验就会好。但是现在看法有些改变,因为目前,很多东西不是需要从头做起的,除非出于学习、版权目的,或者是原先的项目代码烂到不能看而没法维护,没有必要重新实现别人已经实现的东西。大部分软件应该在乎实用性,在不违反版权的情况下,尽量使用已有的东西。

从一开始,我觉得 ibus-sogoupycc 这样一个输入法的技术含量肯定不如 sunpinyin,Linux 下的输入法用 sunpinyin 就不错了,一度怀疑是否要有将 ibus-sogoupycc 写下去的必要。但是现在,我觉得是有必要的,因为在中国大部分有网络的地方,这样一个输入法用起来是更舒服的,至少对我自己来说。

使用信号很弱的无线网,输入起来感觉也不错

出于同样的实用性的考虑,我提供了输入法扩展能力。本来我想提供一个完全兼容谷歌拼音的接口,但是后来觉得谷歌拼音的扩展接口设计得并不好,和目前输入法的无需选词流畅输入有冲突,没有遵循的必要。

开头提到的这个表情在这里: ^_. ,不难找吧。

扩展的设置应该放在用户配置文件中,目前添加一个扩展的方法是:

ime.register_command(key, modifiers, caption, script)

这里,key 和 modifiers 都是数字类型,后两者是字符串类型。

修改用户配置文件后一般要重新启动输入法才能生效,可以右击任务栏上的 ibus 图标,选择重新启动。

Hello world
下面的代码注册了一个用 Alt + H 可以激活的扩展,只要输入法被激活,无论处于中英文状态,都可以用这个热键运行这个扩展。

ime.register_command(("h"):byte(), key.MOD1_MASK, "hello", "ime.notify('hello world')")

重新启动 ibus 之后,按下方形的扩展按钮(ibus-1.2.0.20090927 版本下,方形按钮会消失,这是 ibus 的已知问题,此时通过热键仍然可以运行扩展),可以看到一个标题为 hello 的菜单项,单击它,就可以运行扩展。

输入法扩展菜单


这里,第一个参数是按键,("h"):byte() 表示 h 的 ASCII 码,"ime.notify('hello world')" 是一段字符串表示的 lua 代码,它利用输入法提供的 ime.notify 方法显示了一些内容。

插入系统时间

ime.register_command(key.Shift_R, 0, "插入系统时间", "ime.commit(os.date())")

这里的 ime.commit 也是输入法提供的方法,用来直接向客户端程序输入文字,os.date 是 Lua 标准库函数。这段代码注册了一个用 右Shift 激活的插入系统时间的功能。

Lua 的标准库函数在扩展中都是可以用的,比如可以用 os.execute('mousepad &') 在后台运行一个 mousepad。

执行 Lua 代码

ime.register_command(('L'):byte(), key.SHIFT_MASK + key.MOD1_MASK ,
  "执行 Lua 代码", "ime.execute('ime.notify('..ime.get_selection()..')')")

这段代码注册了一个用 Shift + Alt + L 热键,把选中内容当做 Lua 脚本执行,并用桌面提示显示结果的扩展,这里因为有了 Shift 辅助键,所以要取大写字母 L 的 ASCII 码。其中使用方法 ime.get_selection 获得选定文字的内容,ime.execute 用来把一个字符串当做 Lua 脚本运行,双点号是字符串连接操作。

这个扩展可以比较有用,比如当选定 315+23*6145 这样的表达式之后,运行一下扩展就可以知道计算结果,也可以选定 ime.VERSION 这样的内部变量,查看其内容。甚至可以选定一段 ime.register_command 代码,动态添加扩展 (:

“回音”效果
不知道从什么地方开始流行这种效果,我想说明的是,声明一个函数并且在扩展中调用是可以的:

function echo_effect()
	local s = ime.get_selection()
	for i = 1, #s, 3 do ime.commit((i == 1 and '' or ',')..s:sub(i)) end
end
ime.register_command(('E'):byte(), key.SHIFT_MASK + key.CONTROL_MASK,
  "产生回音", "echo_effect()")

这里简单地使用了 3 个字节 作为步长,所以只能处理纯中文。对文字 “这是回音你懂吗” 使用这个扩展会得到:”这是回音你懂吗,是回音你懂吗,回音你懂吗,音你懂吗,你懂吗,懂吗,吗” :sigh:

全半角切换
输入法本身没有提供全半角切换功能,但是通过扩展可以实现类似功能:

ime.second_punc_map = {}
function toggle_punc_map()
	ime.second_punc_map, ime.punc_map = ime.punc_map, ime.second_punc_map
	ime.apply_settings()
	ime.notify('已切换到' .. (ime.punc_map['.'] and '全' or '半') ..'角')
end
ime.register_command((','):byte(), key.CONTROL_MASK , "全半角切换", "toggle_punc_map()")

注册了 Ctrl + 逗号 作为切换热键,并会用桌面提示显示切换结果。

全双拼切换
可以仿造上例写出:

ime.register_command(0, 0, "全双拼切换",
  "ime.use_double_pinyin = not ime.use_double_pinyin ime.apply_settings()")

前面填写的两个 0 表示这个扩展没有热键,你也可以再加上一句 ime.notify,使得切换的时候有桌面提示。

对缓存的操作
缓存是存在全局的 request_cache 中的,可以直接对其操作:

function show_request_cache()
	for i,v in pairs(request_cache) do
		ime.commit('"'..i..'" => "'..v..'"\n')
	end
end
ime.register_command(0, 0 , "查看缓存", "show_request_cache()")
ime.register_command(0, 0 , "清空缓存", "request_cache = {}")

其中的 ime.commit 方法用来向客户端插入文本,还有一个方法是 ime.request,用来向输入法提交一个拼音请求,比如下面这段代码片段将向输入法提交《春晓》的拼音:

for _, v in pairs
{'chun mian bu jue xiao', 'chu chu wen ti niao',
 'ye lai feng yu sheng', 'hua luo zhi duo shao'} do
	ime.request(v)
	ime.commit('\n')
end

给自己发送飞信
输入法全局配置文件默认加载了 socket.httpsocket.url 模块,可以用它们来访问网络。

比如,下面的代码通过 api.bz 这个在线接口把选定文字内容通过飞信发送给自己:

function send_sms(content)
	http.TIMEOUT = 2
	local res = http.request('https://sms.api.bz/fetion.php?username=15566119320&password=nevermind&sendto=15566119320&message='..url.escape(content))
	ime.notify(res or '飞信发送失败', content, 'info')
end
 
ime.register_command(('m'):byte(), key.CONTROL_MASK + key.MOD1_MASK, "飞信发送", "send_sms(ime.get_selection())")

以上填写的飞信用户名和密码皆为虚构,实际用的时候需要改一下。

简繁体转换和翻译
使用 Google API 来翻译文字,从简体中文翻译成繁体中文就实现了转换成繁体 (:

function google_translate(text, langpair)
	local url = 'http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q='..url.escape(text)..'&langpair='..url.escape(langpair)
	http.TIMEOUT = 1
	local res = http.request(url)
	if res then res = res:match('"translatedText":"(.-)"}') end
	return tostring(res or text)
end
 
ime.register_command(('t'):byte(), key.CONTROL_MASK + key.MOD1_MASK ,
  "转换成繁体", "ime.commit(google_translate(ime.get_selection(), 'zh-CN|zh-TW'))")
ime.register_command(('e'):byte(), key.CONTROL_MASK + key.MOD1_MASK ,
  "翻译成英文", "ime.commit(google_translate(ime.get_selection(), 'zh-CN|en'))")

写在最后

这是一个悲剧。

Lua 作者根本不相信多线程,原因是现在的主流语言中连 a = a + 1 都不是原子的,谈什么多线程呢?

我曾经做过一些尝试,确实让程序多线程地执行 Lua 代码,又共享一些全局数据,不是轻松的事情。我也想到一些解决办法,但是都太麻烦了,于是就偷懒不管那么多了。

这有什么影响呢?影响就是目前输入法执行 Lua 代码是单线程的,扩展中的 Lua 代码会造成阻塞。在有网络请求等操作的时候,要注意控制超时,否则程序可能被认为没有响应了,各种死法都有可能出现 .~.

目前输入法的自由程度到了可以随意 AOE,比如用 os.execute('pkill Xorg'),就可以干掉许多无辜者。正所谓权力越大,责任越大。到底安全与否,就看扩展中的代码自我约束得如何了 ._.

15 thoughts on “关于 ibus-sogoupycc 的扩展

  1. >>我觉得 ibus-sogoupycc 这样一个输入法的技术含量肯定不如 sunpinyin,Linux 下的输入法用 sunpinyin 就不错了,

    很明显Sunpinyin没你想象的那么有技术含量。技术上说,你这个不比sunpinyin差。。。

  2. @Xue : 嗯,确实不错。但是我本意并不是想把它当做是 Shell ,我只是想,像发送飞信或者是一些翻译之类的东西,在这里实现使用起来会比较方便。

    不过目前看来扩展容易把程序弄挂,还没有专心仔细看看是怎么回事 .~.

  3. @xiooli : 我也不相信,当然除了云之外,其他的邮件什么的都不相信。
    不过日常使用云输入法感觉非常好 :p 以至于这是我目前停留在 Linux 而不是 Windows 的首要原因。
    至于监视什么的,我觉得也没什么敏感的信息,爱看就看吧 -,-

  4. 我觉得你还是写篇介绍文章去linuxtoy投稿的好,你有点太低调了,不能“酒香不怕巷子深”。另外archlinux的community里已经有编译好的ibus-sogoupycc包了 ^_^

  5. @ggarlic :

    Archlinux 官方源是把 ibus-* 都加进去了。我知道这件事情,因为我也是 AUR 上软件包的管理者,被移到 community 的时候我收到了通知邮件的。

    至于要不要宣传,我觉得目前还是维持现状比较好。一是现在还有2个Bug在最新版本中Fixed了,还没有发布,不知道有没有其他的问题;二是我确实是比较喜欢低调一些的;还有我毕竟不是搜狗官方,不知道用户数多了起来之后服务器会不会受不了,因为有时候在高峰期明显感觉到服务器那边压力比较大。

    嗯,感谢你的关注,我会在合适的时候考虑向 LinuxToy 投稿的 (:

  6. 腾讯这回又抄云输入法了,看来因搜狗原因导致这个项目可能做不下去的可能性不大了!哈哈!这个输入法是我用过的最好用且有趣的一个了!楼主加油!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>