最开始打算写这篇博文的时候,Keysnail自己的Wiki上还说得不清不楚,一上来就是key.setGlobalKey等几个函数的参数说明,而没有使用说明,也没有vimperator那样的帮助文档(:help),让人云里雾里,闹不清楚。
虽 Keysnail的主要宣传语是“For Vim users, there is Vimperator. For Emacs users, there is KeySnail.”,但其实它跟vimperator还是有很大的不同,vimperator尽力在各方面模仿vim,从快捷键到选项,从配置文件格式 到帮助系统,而keysnail基本上只有快捷键,甚至缺省提供了一套仿emacs的,还提供了一套仿vim的。
当然,它还是有一些Emacs特色的,比如可以用C-1..C-9, C--, C-u做为前缀参数,有rectangle操作方式,有M-x命令;
但总体而言,keysnail其实跟keyconfig比较象,主要就是将某个快捷键绑定到一段javascript上,所以主要的配置工作就是编辑自己的 .keysnail.js 文件。
我弃用vimperator改用keysnail的主要原因是:1)vimperator的单个字母跟很多网页应用(比如Google Reader, GMail, 以及Brief这样的Firefox扩展)的快捷键相冲突; 2)想自己添加一些新功能到某个快捷键总是觉得麻烦(感觉keysnail就简单多了); 3)vimperator中,在textarea中输入文字时需要在模式间来回切换,感觉很麻烦;
* 快捷键设置
如果你只是想修改哪个快捷键对应哪个功能,可以直接在Keysnail设置界面修改(【工具.Keysnail. Open proferences dialog】。界面操作比较简单,自己摸索一下即可。
* 添加新的功能(并绑定到快捷键)
如果想扩展一些快捷键功能,则需要了解如下几个函数:
key.setGlobalKey(keys, func, ksDescription, ksNoRepeat);
key.setEditKey(keys, func, ksDescription, ksNoRepeat);
key.setViewKey(keys, func, ksDescription, ksNoRepeat);
key.setCaretKey(keys, func, ksDescription, ksNoRepeat);
setGlobalKey 设置的快捷键是全局有效的,即使你在输入框中、Caret模式下,这些快捷键都有效;
setEditKey 设置的是在编辑框中的快捷键,对于Firefox自身的输入框(XUL)和HTML输入框都是有效的;
setViewKey 模式设置的是网页浏览时的快捷键,不再
setCaretKey涉及到caret模式,这是网页浏览的一个特殊模式,该模式下Firefox能显示光标所在位置,且能移动光标,下面评论部分有详细说明。
以C-f为例,配置方式如下:
key.setEditKey( ' C-f ' , function (ev, arg) {
command.nextChar(ev);
}, ' Scroll right ' );
keys: 键名的写法基本上跟Emacs里面一致,比如C-f, M-f,<up>。补充两点: 1)对于C-x C-f这样的组合按键,需要写成['C-x', 'C-f']; 2)如果你想为同一个功能绑定两个组合键,需要写成[['C-x', 'K'], ['C-x', '5', '0']]
func: 这里需要提供一个函数,即由上述按键触发的处理函数,函数形式为 function (ev, arg)。keysnail可传入两个参数
第 一个参数ev是触发按键的事件,从这个参数中你能够得知事件的详细内容,比如到底是按了什么键(ev.charCode, ev.ctrlKey, ev.metaKey等),是在哪个位置按的(ev.clientX, ev.screenX等), 是在哪个输入框按的(ev.target等),详细内容可参看MDN Docs: DOM Event —— 不过大多数时候你不大会用到它;
第 二个参数arg,跟Emacs里面的arg一致,是由C-1..C-0, C-u, C--等前缀键传递过来的。注意,如果要使用这个参数,需要将setXXXKey的最后一个参数ksNoRepeat设置为true(缺省为 false),否则keysnail会将C-2变成重复调用你的函数2次,C-u变成重复4次。
ksDescription: 快捷键功能说明,帮助你记忆的,随便写。此参数可省略。
ksNoRepeat: 设置前缀参数(prefix argument, 即C-1..C-0, C-u)的使用方式,为true时前缀参数传递给处理函数func, 为false时重复调用func若干次;此参数可省略,缺省为false。
示例: 用 C-x 8 - 输入特殊字符'…'
var aInput = ev.originalTarget;
var value = aInput.value;
var originalSelStart = aInput.selectionStart;
aInput.value = value.slice( 0 , aInput.selectionStart) + " … " + value.slice(aInput.selectionEnd, value.length)
aInput.selectionStart = originalSelStart + 1 ;
aInput.selectionEnd = aInput.selectionStart;
}, " Input … " , true );
* Ext -- Keysnail里面的M-x
Keysnail也提供了Emacs里面的M-x方式来调用某些功能,不过缺省没有提供任何命令,你得安装一下Builtin command as Ext这个插件,这样Keysnail内置的很多功能都可以以命令名的方式调用了,比如M-x restart-firefox, M-x select-next-tab。 另外很多插件都是通过ext的方式来提供新命令的(缺省不绑定快捷键,留给用户自己来决定)。
要自己添加新的命令也很简单,在自己的.keysnail.js的PRESERVE区(即{{%PRESERVE%和%PRESERVE%}}之间)按如下格式添加代码就可以了
ext.add(cmdname, func, desc)
cmdname 是命令名称,即M-x后输入它来激活相应的功能
func 为功能实现,跟上面的key.setXXXKey里面的func是一回事
desc 是描述,随便写
示例: 下面代码实现了vimperator里面p命令的功能(也免除了单独安装Paste and Go扩展的必要)
var url = command.getClipboardText();
if (url.indexOf( " :// " ) != - 1 ) {
window._content.location = url;
} else {
BrowserSearch.loadSearch(url, false );
}
}, " Paste the URL or keyword from clipboard and Go " );
如果想将这个paste-and-go绑定到某个键的话,可用下面的方式:
ext.exec( " paste-and-go " );
}, " Paste and Go " , true );
* 如何在keysnail中得到vimperator里面的xx功能
keysnail 缺省带有一套仿vim 的配置,跟vimperator 的相似度也挺高,不过还是缺一些功能:
- o/t (即:open/:tabopen): 在keysnail中是一样的:open/:tabopen,也可以用搜索引擎的缩写(比如:tabopen go keysnail——如果你在搜索引擎框里配置了go这个缩写的话),不过缺省没有绑定到快捷键,你想要的话,可自行绑定 shell.input(":open ")这段代码
- QuickHints (f/F/;y/;Y等): 输入几个字母就打开链接/复制链接;keysnail缺省不带这个功能,你需要安装HoK插 件,使用方法:M-x hok-start-foreground-mode, M-x hok-start-background-mode,M-x hok-start-extended-mode, M-x hok-start-continuous-mode 或者将这几个命令绑定快捷键;如果想跳到任意段落(而不仅仅是链接上),可再安装Caret hint插件;
- C-a和C-d: 对URL中的最后一个数字加1或减1,一般用于浏览分页文章。这个功能缺省没有,见文末评论部分的补充。
- [[ 和]]: 即上一页、下一页,对于浏览分页文章、论坛之类的很有用。这个功能缺省没有,见文末评论部分的补充。
- p和P: 即Paste and Go和Paste to new tab and Go。这个功能缺省没有,见文末评论部分的补充。
* 一些类似Emacs的特色
- 前缀参数: 可在设置对话框中设置使用C-1..C-0,M-1..M-0或者C-M-1..C-M-0,这表示传递相应数值给处理函数;另外还有除了C--和C-u;
- kill ring: 跟Emacs里面一样,keysnail 里面内置了“剪贴板历史”,你可以用M-y粘贴上一个、再上一个;
- rectangle: 在输入框中,你也可以用Emacs 里面的矩形块操作,比如用C-x r t 给矩形块中每一行添加文字;
- keyboard macro: 也是用F3录制,F4结束录制或者回放,不过我没找到记录为代码并编辑的地方;
- anthing: keysnail自身就提供anything风格,它的M-x用的就是这种,而且有不少插件都利用了keysnail内部提供的prompt.reader()和prompt.selector()的机制来让用户挑选备选项,比如Tanything可以让你用anything的方式来挑选要跳到哪一个标签页;bmany可以用来选取书签;
参考资料
- Keysnail Wiki: Tips
- keyconfig快捷键的自定义
- Xiao Shan » Customize firefox shortcuts – 自定义firefox快捷键
- Xiao Shan » [KeySnail]编辑模式下使用可输入字符作为快捷键
其它小技巧可查看下面的评论部分,我会时不时将新发现的内容添加上去。
另,我的配置文件放在这里,有兴趣的可以参考: http://code.google.com/p/bamanzi-misc/source/browse/trunk/firefox/keysnail/.keysnail.js