畅玩emacs:一种全新的emacs快捷键使用方式(总结贴)

早就想就这个问题写个总结贴,一直没动手,看到 Action的总结性贴子 Windows10上畅行无碍地使用emacs的11步骤 终于决定动手开写。有样学样,也发布到了头条和github,链接在文末尾

感谢 @ owensys 在原帖 我的emacs按键使用方式-用shift中的回复


如果你是emacs新手或者觉得emacs的默认按键设置非常难用,本文将帮助你找到一种适合自己的快捷键使用方式。

注意:本文主要针对主流笔记本键盘布局(类似下图),需要你对emacs hydra有一些了解。

苹果第一款12寸macbook的键盘布局

一句话概括全文:不要再用你的小拇指按ctrl键了。

emacs用多了小拇指疼,关节疼,得腱鞘炎等一直是emacs被吐糟的地方,但事实上重度emacs用户通常都不会完全使用原生快捷键,会按自己的方式对快捷键进行一番改进,使emacs用起来足够顺手,甚至是全键盘操作,不用鼠标。

改进emacs的快捷键操作通常有这几种方法:

1,交换ctrl和caps lock键;

我用过这一办法,产生的主要问题是换电脑换系统后和用别人电脑(或别人用我电脑)时会不适应,如果你的电脑并不完全是自己使用,而是公共财产(如属于公司等),显然不适合在系统级别修改键盘映射,这会影响到所有用户和电脑内的所有软件。

2,使用evil;

使用emacs内的vi模拟器evil,如果本身是vim用户,在emacs内使用vi是个好办法,但也有很多人并不喜欢vi,希望进入编辑器后直接就能打字。如果中文输入法用得比较多,中文输入法下使用vi模式切换时会有一些问题要解决,但显然没有英文输入顺手。

3,换一个更适合emacs的键盘

用HHKB pro,Filco ,静电容键盘,自定义键位的poker,人体工程学键盘…因人而异,这些都是不错的选择,但我个人觉得普通笔记本自带键盘就不错(只要shift键足够大)

4,其它方法

使用Dvorak键位,掌压ctrl键,中指按ctrl键,ctrl键和alt交换等等。

使用shift键

开头已说点明本文针对主流笔记本键盘布局,而主流笔记本键盘布局对ctrl键都很不友好,ctrl键很小,甚至只有左ctrl键,没有右ctrl键,但shift键却没有缩水,通常比capslock键,enter键都要大一些。

如果是传统台式电脑键盘,enter键,右shift通常比capslock键,左shift要大些,并不是对称的,笔记本则设计成左右大小对称的比较多。

左右shift键就是键盘上仅次于空格的第二大键,可以用小指、无名指或无名指、中指一起按,随时都是两根手指一起按,无疑比单指按ctrl好太多。

当我发现我在emacs上并没有充分利用起shift键,shift键使用的频率还不如alt键,ctrl键时,我就想能不能把shift键当ctrl键用。尝试之后发现可行。

因为emacs不能识别shift键按下,把shift键当快捷键用后导致无法按caps lock键后正常输入大写字母,caps lock键的作用成为了类似vim中的esc键,也成了一种模式切换。

首先要解决大写字母输入的问题,我用hydra写了一个函数来解决。代码如下:

 (defhydra hydra-caps ()"l"
    ("a" (insert-char 65))("b" (insert-char 66))("c" (insert-char 67))
    ("d" (insert-char 68))("e" (insert-char 69))("f" (insert-char 70))
    ("g" (insert-char 71))("h" (insert-char 72))("i" (insert-char 73))
    ("j" (insert-char 74))("k" (insert-char 75))("l" (insert-char 76))
    ("m" (insert-char 77))("n" (insert-char 78))("o" (insert-char 79))
    ("p" (insert-char 80))("q" (insert-char 81))("r" (insert-char 82))
    ("s" (insert-char 83))("t" (insert-char 84))("u" (insert-char 85))
    ("v" (insert-char 86))("w" (insert-char 87))("x" (insert-char 88))
    ("y" (insert-char 89))("z" (insert-char 90))
    ("<SPC>" nil))
(global-set-key (kbd "L") 'hydra-caps/body)

上面代码中看到我将其绑定到了shift+l键,L进入大写字母输入模式,空格退出大写字母输入模式,当然也可以按其它键退出大写字母输入状态。

L进入大写字母输入模式

上面代码是连续输入多个大写字母的,如遇到编程时的驼峰命名法(DataBaseUser)时,大写输入状态连续换几次,这时需要有一个输入单个大写字母后立即退出大写字母输入状态的功能,我写了一个hydra函数来实现。代码如下:

(defhydra hydra-shift () ","
   ("a" (insert-char 65) :exit t)("b" (insert-char 66) :exit t)
   ("c" (insert-char 67) :exit t)("d" (insert-char 68) :exit t)
   ("e" (insert-char 69) :exit t)("f" (insert-char 70) :exit t)
   ("g" (insert-char 71) :exit t)("h" (insert-char 72) :exit t)
   ("i" (insert-char 73) :exit t)("j" (insert-char 74) :exit t)
   ("k" (insert-char 75) :exit t)("l" (insert-char 76) :exit t)
   ("m" (insert-char 77) :exit t)("n" (insert-char 78) :exit t)
   ("o" (insert-char 79) :exit t)("p" (insert-char 80) :exit t)
   ("q" (insert-char 81) :exit t)("r" (insert-char 82) :exit t)
   ("s" (insert-char 83) :exit t)("t" (insert-char 84) :exit t)
   ("u" (insert-char 85) :exit t)("v" (insert-char 86) :exit t) 
   ("w" (insert-char 87) :exit t)("x" (insert-char 88) :exit t)
   ("y" (insert-char 89) :exit t)("z" (insert-char 90) :exit t)
   ("," (insert-char 44) :exit t)("," (insert-char 65292) :exit t)
   ("<SPC>" counsel-switch-buffer "" :exit t);;切换buffer
   ("." counsel-imenu "" :exit t)("。" counsel-imenu "" :exit t)
   (";" nil)(";" nil) )
(global-set-key (kbd ",") 'hydra-shift/body)
(global-set-key (kbd ",") 'hydra-shift/body)

上面代码中可以看到我绑定了“,”号进入单个大写字母输入状态,而输入原本的“,”号则需要按两次“,”键才能正常输入“,”号,而因为我在中文输入法下使用emacs比较多,我把中文的",。;"符号都做了绑定,还加了些其它功能。

使用了“,”号后大写字母输入的问题完全解决,这时就可以自由使用shift来绑定emacs中让你不爽的快捷键了。

比如常见的光标移动:

(global-set-key (kbd "P") 'previous-line);与ctrl+p一致
(global-set-key (kbd "N") 'next-line);下移动光标
(global-set-key (kbd "F") 'forward-char);向前移动一个字符
(global-set-key (kbd "B") 'backward-char);向后移动一个字符
(global-set-key (kbd "A") 'move-beginning-of-line);移到行首
(global-set-key (kbd "E") 'move-end-of-line);移到行尾

注意:这里的用法不是取代emacs原生快捷键,是在emacs原生快捷键的基础上新增快捷键,可以与原生快捷键兼容一起共用。tab +shift,ctrl+shift这些在emacs下都还是以前的功能,不会有任何变化。

有一部分emacs用户不愿意改默认快捷键的原因是很多个性化定制都是因为还没遇见更复杂的情况,所以迫不得已,尽量不改

但我这里的用法不是改快捷键是增加快捷键,默认快捷键一直都是可用状态,也不需要有切换成默认快捷键这个步骤,所有不会有很多个性化定制都是因为还没遇见更复杂的情况这个问题

快捷键这东西非常个性化,emacs用户通常是用到哪儿绑到哪儿,当我发现某个emacs快捷键有点难按,就用我的方法绑定一下即可,原生好按也就不用绑了。

举例:我发现最新版org-mode输入 <s后按tab不会展开了,在我针对org-mode的hydra键绑定里面加了两行elisp,然后再绑定快捷键解决。

(defhydra hydra-org-mode () "org" 
   ;;……
   ("c" (progn (insert "#+BEGIN_SRC \n\n#+END_SRC")
          (move-end-of-line -1)) "org代码片段模版" :exit t) )
(global-set-key (kbd "C") '());;清除C的默认绑定
(add-hook 'org-mode-hook (lambda ()
   ;;……
   (local-set-key (kbd "C") 'hydra-org-mode/body) ) )

这里我绑定的快捷键是C_c,当然这个例子中的问题还有更好的解决办法,使用(use-package org-tempo),<q <e 之类的也可以一并解决。这里感谢@deerainw

最后补充

这个修改只是在emacs层面改动有效,对键盘本身的按键映射没有影响,不会改了后电脑里其它的软件按键也跟着变,影响不到电脑里其它任何软件的正常使用。

在vscode中可以识别shift键,也可以用这个按键方法,而且不影响capslock键之后输入大写字母,vsc也有个叫hydra的插件,但完全不是emacs的hydra。

emacs中有很多好玩的功能,需要在使用过程中才能发现。被称之为“神之编辑器”并不是浪得虚名。


在github中查看本文 //github.com/wsug/emacs-key/blob/master/emacs-key.md

在头条链接中查看本文 //www.toutiao.com/i6867441432903287308/

7赞

不知道为什么,我的id昵称wsug在github等N多个网站上用都没问题可以用,但头条就是不让我用,硬说我的账号名称无意义要给我重置,非让我改。只好改了。

为什么我用shift按着这么别扭呢,感觉还没有capslock舒服。

我是将command映射到ctrl,将capslock映射到command, ctrl映射到capslock。相当于三者做了循环调换。现在,基本用不到小拇指,都是用大拇指按,很爽。

个人的一点思考和不成熟的观点: image

这是一副完美的Emacs键盘。

为什么呢?

首先Emacs最高频的按键是Control,我们把空格键盘左右两侧的Command设置成Control。 拇指稍微一弯就能按到这两个键。
其次Emacs第二高频的键位是Meta,将Option设置为Meta,左右手的无名指能毫不费力的按到这两键。

设置好这两个键位之后,在Emacs里不需要记忆一个快捷键。

我觉得用shift做快捷键会导致emacs中和外部打字的方式发生变化,打一个相同的字母,按的键却不同。我觉得有点不太好。

根据个人使用习惯来吧,我那个时候主要是在中文下使用emacs,很少用shift来输入大写字母的,结果就发现我ctrl按都按坏了,shift键却基本没动,好好的,用得少还占那么多空间浪费啊。

但如果基本全在英文输入状态下使用emacs,经常性的用到shift输大写字母,甚至使用频率不低于ctrl就没必须改了。

总之满足个人使用习惯。让键盘上每一个键都不浪费、物尽其用就好。

发现我的贴子(就是本贴一楼)在我不知晓的情况下,被转到其它网站上去 这里1 这里2 也未标明出处,google也能搜索到,这种情况有人遇到过吗,怎么处理才好

我觉得你可能需要问一下头条管这些的人(这也应该是在头条被抓的),

因为管这些规模越大成本越低。

抄袭还不打招呼有点可恶了

一把hhkb解决你的问题 , 使用起来爽到飞起 .

1赞

真是个好想法

学习了. 有一个疑问:
可不可以对没有覆盖到的head键都采用诸如(self-insert-command)呢?
比如说",<小写字母>"输入大写字母之类的, 我希望如果","后接的不是小写字母而是诸如数字或符号, 那么直接输入数字或符号. 或者更理想的是同时补上一个",<数字或符号>". 是否有配置可以做到呢?
我看到的 :foreign-key 但似乎只能设置nil, 就是什么都不做.
当然我还可以绑上每一个键, 但我想偷懒:-<

额, 突然发现一个更严峻的问题, 似乎不能绑<数字键>, 因为会被当成prefix? 这个有解嘛? :mask:

似乎只能一个键一个键的绑定,不清楚如何同时绑定多个键。

绑定数字键可以的,但是绑定的数字键我这里测试用键盘小键盘区无效,非得用键盘最上方的那一排数字键才有用

(defhydra hydra-shift () ","
  ("1" (switch-to-buffer "*Messages*") "" )
  ("2" (shell) "" )
  ("3" (ibuffer) "" )
  ;;……
)
1赞

谢谢!! 我发现是我忘了为(self-insert-command 1)加这个参数1.蠢哭了 :upside_down_face:
还有一个疑问就是如果我可不可能在emacs中在所有keymap功能前劫持, 来建立一层映射,
实现类似用,[来打出{(避免按shift), 同时所有{的功能也都被承接(包括自动匹配或移动)?

这个我也不知道如何实现,,[ 仅仅只是打出{,可以一个个的写

 ("[" (insert "{") )
 ("]" (insert "}") )

感觉按shift来输这些标点符号也还好

嗯, 只是这样改的话只能实现插入{, 但是比如在lispy/eviil下的移动模式, 还有自动匹配}应该都必须重新从各个keymap定义了吧.

你是在说输入法吧

1赞

啊呀, 这个我还真没想过, 好像确实是可以通过输入法来增加这一层映射哈! 我从来没有用过emacs这方面的功能!
打开了新世界的大门!? 官方文档是33.11 Input Methods, 有什么推荐参考的包么?

看看自带的输入法包吧

1赞