键盘是很多人经常使用的工具。打字机的键盘用于打字,但电脑的键盘不只用于打字,更多情况用于控制软件的行为。但键盘的键位还是以字母键为主,控制键基本位于不好按的边缘位置。但软件默认快捷键基本都是 Ctrl + a、Alt + b、Ctrl + Alt + c 这样,并不好按。更重要的是,除了 Vim 等少数软件,多数软件在非文字编辑状态是不响应直接的字母按键的,控制这样的软件,放着手指正下方下的字母键不能用,却要去找边边角角的 Ctrl、Alt、Win、Home、End、PgUp、PgDn 等按键十分不合常理。

其实效率只是一方面,我不是很注重的一方面。在我看来,电脑是各种机器的结合体,比如听歌看电影时是播放器,看书看图片时是浏览器,存放文件时是存储器,而打字机也只是其中的一种机器,而且对于很多人来说,并不是最常用的一种。当我用单独的字母按键操纵一台电脑时,我感觉这真的是一台机器,每个按键都是一个按钮,按下去就给机器发送了指令,控制这台机器会用一种淋漓畅快的感觉。但如果我只能按 Ctrl、Alt 这些辅助键的同时再按字母,才能实现一种功能,那这只是伪装成另一种机器的打字机,并不是一个键还是两个键的问题,这有着本质的不同。

提到单按键功能,不得不提 Vim 。提起 Vim 的特点,很多人说多模式。这确实是很重要的特点,但我感觉这不是最基本或者最重要的。最基本也最重要的特点是单字母键即功能。Vim 是多模式,一方面因为键盘按键数量有限,另一个很重要的原因是 Vim 是编辑器,在操作编辑器时,键盘兼任输入字母和控制功能两部分工作,如果单字母即功能,必然要实现成多模式。这也造成了 Vim 操作的复杂性,Vim 没有变成编辑器的主流(虽然用户已经不少了)。

但并不是所有的软件都这样。除了文字编辑器,我们在使用其他大多数软件的过程中,很少需要输入文字,多数情况是在给软件发生一个特定的指令来控制某个功能,比如让播放器播放下一首歌,让浏览器显示一个超链接的内容。这样的软件,应该让单字母键成为功能键(同时不用像 Vim 那样设计成多模式),而不是使用复杂的Ctrl、Alt等。但因为种种原因,很少有软件这么做,导致在很多人看来,快捷键都成了摆设,除了寥寥几个非常常用的,记不住,不好按,还不如直接点菜单。

个人感觉,可以考虑给软件实现这样一个交互界面。在主界面可见的功能附近都显示一个字母,直接按字母和用鼠标操作是相同的。对于主界面不可见的功能,可以方便调出按键提示,显示其他按键对应的功能是什么,作为菜单的一种替代。而连续的多个按键,作为子菜单的替代。当功能过多时,可以考虑使用 Ctrl、Alt 等组合键,但是在单字母已经不够用的情况下。用带说明的快捷键列表代替菜单,有很多好处。因为菜单并不是一个很好的设计,它当然有它的优点,比如直观、形象,如果只是试用一下这个软件,那么很好。但操作便捷性上很成问题,而且难于记忆。当我使用了几次用 p 键来发播放器的播放指令后,我就可以记住了。但如果播放功能在菜单的第 4 项,即使我用了几十次,还很难记住它的位置,更不会通过数字 4 来直接触发这个功能(菜单上有快捷键就是另一回事了,这个菜单本身无关)。当一个软件菜单栏布满密密麻麻的菜单,有些菜单还有几层子菜单,有些功能对应着莫名其妙的复杂快捷键,其余功能直接没有快捷键,就可以想想这个软件的长期用户是怎样的痛苦了。

当然这只是题外话。现有的软件已经是这样了,我们不可能重新开发一遍,但这并不意味我们没有其他办法改善操作体验。

再来仔细看一下我们熟悉的键盘:

键盘键位

正常情况我们的手是在 asdf jkl; 空格 左Alt(左拇指一般能落在左Alt键上,但右拇指一般只能落在空格键上,不然很不舒服) 10个键上的。只有按这10个键是不用移动手指的,也是最方便的。

退而求其次的话,只移动一个键位就能按到的,有几乎全部的其余字母键、'、CapsLock、/、Shift、右Alt。而常用的Ctrl、Tab、Esc、回车、方向键、编辑区键等继续被排除在外了。以我通常的经验,在以上这些键之外,盲打的错误率会显著提高,即使像我这样的电脑爱好者,也无法做到盲打顶端数字键、编辑区键(Home、PgUp之类,笔记本键盘的键位还不统一)、F1~F12、和部分符号键。即使有人熟练到能全键盘盲打,打这些边边角角的键和打字母的效率也是不一样的。也就是说,对于多数人,除了字母键和少数控制键,按其他键之前都是需要先看下键盘的。

可以想象如果一个软件的快捷键都是Ctrl + F3、Alt + F6、Shift + End 这些,一方面需要记忆这些和功能几乎不相干的按键,一方面又要看键盘上的按键位置,有多少人愿意用,除非某个功能太常用了,已经形成条件反射了(比如Alt + f4,很多人都知道和使用这个快捷键,几乎是一个奇迹,但有人能记得Alt + f3在某个软件有什么功能吗)。

但如果释放单字母键的控制功能,那么a-z直接就有了26个功能,对于不复杂的软件已经足够了。如果不够的话,Alt加字母,又有26个。如果还不够,Shift加字母,也就是大写字母,又是26个。Alt和Shift都要比Ctrl好按。如果还不够,Ctrl加字母,又26个。已经超过100个了,什么软件还不够用?软件操作确实复杂得很的话,上双字母键,26*26,直接676个,即使是双字母键,也比Ctrl+数字键好按,有必要上Ctrl+F1、Ctrl+Shift+e这些不好按或者复杂按键吗?

用单字母键的另一个优势,在于字母是可以和功能相关的。比如在文件处理器中,我要编辑一个文件,Edit,我首先就想到了e,这几乎是不用记忆的事情。但如果这个快捷键是ctrl+e,就不一样了,我想到了e,但还得接着想是ctrl+e呢,还是alt+e呢,甚至ctrl+shift+e?复杂性剧增。算了,想不起来了,还是去找菜单吧……

那么如何安排这些字母呢?

我们可以先了解下现在系统和软件是如何使用组合键的,以Windows系统为例,Linux和Windows差别不大,OSX有些不同,但道理上差不多的。

Win 键:用于系统功能。比如打开搜索框、文件管理器、系统配置界面、投影设置等。但并未占满所有 Win+字母,少有其他软件使用 Win 键。

Ctrl 键:一般是软件中的首选组合键。如果软件想添加一个快捷键,一般从 Ctrl + 字母数字开始。系统自身很少用Ctrl键。

Alt 键:系统中用于窗口、菜单等操作,比如关闭窗口、打开菜单、定位控件等,一般 Alt + 字母键不直接对应软件的某项具体功能。

Shift 键:一个只用于输入大写字母。另外当软件的 Ctrl + 字母数字不够用时,一般会用 Ctrl + Shift + 字母数字,这是一系列非常难按的快捷键,而且一般人都很难记住。

F1~F12:某些软件会将其作为功能键,但不是很多。除了直接使用,还有用 Ctrl + F1~F12 的情况,异常难按的组合。

右 Alt 键、右 Ctrl 键和右 Shift 键:功能一般和左边的一样,但人们一般习惯按左边的,很少按右边的。也确实比左边的难按(右拇指要移动才能按到右 Alt,右小指要应付的符号键太多了,顾不上右 Ctrl 和右 Shift 了)。

编辑区键(Home、Delete、Backspace等):除了常用的 Delete、Backspace,其他的几乎都成了鸡肋。很多使用多年电脑的人甚至没按过几次 PgUp 和 PgDn(包括我)。而 Backspace 和 Delete 都不大好按,尤其是 Delete,位置还和具体键盘有关,但它太重要了,不好按也得按。

方向键:比较常用的按键,但需要把手整体移动到键盘右下方才能按到,非常不方便。

回车键:几乎是整个键盘最重要的按键了(打字时(英文直接打空格,中文选字词)最重要的是空格,控制时最重要的是回车,虽然某些界面上空格和回车是一样的功能,但按空格总感觉有些没底,没有回车靠谱,比如空格总容易多按几个)。但这么重要的按键需要照顾很多按键的右小指移动两个键位才能按到,真是苦了它了。

那我们设想重新安排一下按键,先从系统功能开始。

已有的几个 Win + 字母 快捷键是不用动的,而且有的改不了(比如 Win + l)。但除此之外还有一些未使用的 Win + 字母。因为 Win 按键不如左 Alt 和 Shift 好按,可以设置一些不常用的全局功能。比如启动某些常用的软件。一般常用的软件有限,剩余的字母基本够用了,如果不够的话,剩下的基本都不是那么常用的了,估计也未必能记得住快捷键,可以用在快捷启动软件(如 Launchy)直接敲软件名。

除了系统功能,剩下的就都和具体的软件相关了。

首先我们需要一系列全局快捷键,用来解决回车、Backspace、Delete、方向键等常用按键位置别扭、窗口操作快捷键复杂等问题。考虑到键盘上最好按的组合键是左 Alt (左拇指可以直接放在上边),所以非左 Alt + 字母莫属。这一系列快捷键在所有软件都是可用的,因为基本没有软件直接用 Alt + 字母作为功能键,所以基本上说可行的。对于不常用的 Alt 定位控件场景,可以用右 Alt 操作(右拇指按右 Alt 相对还是比较方便的,没有右 Ctrl 和右 Shift那么难堪)。

然后剩余的按键都归具体软件所属了,也就是同一个快捷键,在不同的软件的功能很可能是不一样的。

首先安排的自然是单字母键,26个,用来处理最常用的功能。设置时,要同时考虑操作的便捷和语义的联系。有一些约定俗成的习惯可以参考,比如j、k、h、l用于方向,q用于退出,e用于编辑,x用来删除等。但因为不同的软件功能完全不同,不用拘泥于此,具体场景具体分析,按得舒服就好。

如果单字母键不够用了,优先考虑左 Shift + 字母,也就是大写字母,因为除了左 Alt 外,最方便的组合键就是左 Shift 了(当然可以考虑互换 CapsLk 和 Shift,但对 Vim 用户来说,互换 Esc 和 CapsLk 也许更合适一些)。

如果大写字母也不够了,再考虑 Ctrl + 字母,Ctrl 虽然在键盘的位置不是很好,但大家 Ctrl + c、Ctrl + v 用习惯了,倒也还好。

如果还不够的话,就不要再考虑 Ctrl + Shift 之类组合了,直接上双键吧。但上双键也是有策略的,比如有一个双键 ad,那么 a 就不能当单键使用了。但一个 a 换来了 26 个双键,具体怎么用就好权衡了。一般拿出几个键来做双键前缀就可以了,没有必要大动干戈。如果需要超过5个双键前缀,就需要直接考虑多模式(比如增加一个命令模式,进去后直接敲命令然后回车)了。

当然如果以上只是空想就没什么意思了。

下面是我设计的左 Alt 键组合功能,这些功能在所有软件都是可用的(当然能否发挥作用要看具体软件了):

全局快捷键列表

具体软件的话,以 Total Commander 为例。因为文件操作是非常复杂的,我一共映射了全部小写字母(包含一些双键)、全部大写字母、全部 Ctrl + 字母、全部的F1~F12、大部分键盘右侧符号等,一共120多个按键组合,论复杂可以说无出其右了。当然我不可能全部记住,实际使用时是可以打开按键帮助和补全提示的,要比去菜单找功能方便很多。

按字母排序
按功能排序

最后也是最关键的,如果自己设计出了一套适合自己的快捷键方案,如何实现呢?

这就要推荐一下 VimDesktop 软件。

VimDesktop主页

虽然它名里带 Vim ,但对不熟悉 Vim 的朋友也完全使用,可以随意按照自己的心意修改按键。以上的按键列表都是默认配置中内置的。修改的话直接改配置文件就可以,很方便。

比如:

<la-h>=<left>[=normal]
<la-i>=<home>[=normal]
<la-j>=<down>[=normal]
<la-k>=<up>[=normal]
<la-l>=<right>[=normal]
<la-m>=<WindowMax>[=normal]

la即左 Alt,无需文档就可以看懂按键的功能。

如果需要对某个软件定制快捷键方案,添加插件也是非常方便的。以自带的 WinMerge 软件为例:

WinMerge:
    ; 功能注释,可选
    vim.comment("<WinMerge_NextDiff>", "下一处不同")
    vim.comment("<WinMerge_PrevDiff>", "上一处不同")
    vim.comment("<WinMerge_FirstDiff>", "第一处不同")
    vim.comment("<WinMerge_LastDiff>", "最后一处不同")
    ; 省略若干行

    ; normal模式
    vim.mode("normal", "WinMergeWindowClassW")

    vim.map("j", "<WinMerge_NextDiff>", "WinMergeWindowClassW")
    vim.map("k", "<WinMerge_PrevDiff>", "WinMergeWindowClassW")
    vim.map("gg", "<WinMerge_FirstDiff>", "WinMergeWindowClassW")
    vim.map("G", "<WinMerge_LastDiff>", "WinMergeWindowClassW")
    ; 省略若干行
return

<WinMerge_NextDiff>:
    Send, !{down}
return

<WinMerge_PrevDiff>:
    Send, !{up}
return

<WinMerge_FirstDiff>:
    Send, !{home}
return

<WinMerge_LastDiff>:
    Send, !{end}
return

; 省略若干行

这里是用按键映射来实现的,如果软件的功能对应着快捷键,这是最容易实现的方法。如果没有的话,看看是否有可用的Com对象、消息接口、命令行工具等,如果都没有,可以再看下能否模拟菜单点击,甚至模拟鼠标操作。如果都搞不定,那就没有办法了。

代码是 AHK 写的,AHK 最方便的地方在于:

  1. 可以很容易地处理按键相关的操作,比如按某些键执行某些功能。
  2. 可以用最简单的环境(仅需要一个不足1M的AutoHotkey.exe,加一个顺手的编辑器),就可以开发不复杂的图形界面软件(用其他语言或者开发工具一般要安装体积庞大的环境才可以开发)。
  3. 可以很方便地调用COM对象和Win32 API。

用来开发这样的软件实属绝配。