九月十月似乎莫名变得很忙,十月份的 Inktober 就别说参加了,基本上是连看网上别人的作品都没太顾得上,感觉我入职以来还从来没有这么忙过,感觉居家令对我生活影响最大的似乎还是 work life balance 的改变,当然所有的事情也都纠缠在一起,也有可能是我现在参与的项目更多或者更麻烦的缘故,但那也难保和居家令没有关系,也许许多人宅家都会去做更多的事情,所以合作的项目才变多的呢?总之就是很忙,不过再忙也还是抽空组装了两个新键盘 XD,这里分享一下过程和经验。

这次的两个键盘都是日本人设计的,一个是 split 的 Corne,另一个是伪 split 的 Reviung41。Corne 可以安装 OLED 屏幕显示一些好玩的东西,我也会分享一下定制 OLED 显示的方法。

Corne Cherry Build Log

Corne 是一个 ID 叫 foostan 的日本人设计的一个分离式键盘,最初的灵感来源似乎是一个叫做 Helix 的分离式键盘,也是有日本人设计,结构很简单,两个方形正交键盘,基本上拼起来就是一个 5x12 的 Preonic 再多了中间几个键,最开始发布出来的时候似乎在日本非常火爆。Corne 做的改变主要有以下几点:

从正交布局变成了按列错开的布局。标准键盘的布局是按行错开,似乎没有什么特别的道理,正交布局感觉更美观也更简便,但是也很难讲就一定比按行错开更优,但是按列错开的布局则一般认为是在人体工程学的行列,因为如果你把手指正常弯曲放在桌平面上,基本上构成的弧线就是和这里的布局是一致的。所以从也许是分离式键盘的鼻祖的 ErgoDox 的众多分离式键盘都采用这样的按列错开的设计。Corne 这样的列错开的距离其实是挺小的,基本和玩完对齐的正交其实没有太大的区别,也有诸如 Kyria 之类的比较 aggressive 的设计,特别是在小拇指那边下降距离非常多的设计(它还提供了可打印的图纸让你和自己的手形做对比)。在这个网站可以查看和比较各种常见的分离式键盘的形状和布局。

底排功能键简化。我在用自己的 4x12 Planck 键盘的时候发现最下面一行的功能键除了距离中间的空格键最近的一两个键之外,其他的按起来都非常别扭,需要让手完全离开原来的位置,所以我几乎也从来不会去按那几个键。经过一段时间之后总结出来我下面主要需要空格键、两个 Layer 切换键 Raise 和 Lower,以及在 Mac 下各种快捷键需要的 Cmd 键就够了,所以像 Corne 这样的精简布局刚好够用,由于对称关系多出一个键可以设置成 Alt 键,分离式键盘有两个空格,如果需要的话可以把另一个设置为回车或者退格之类的。我后面会再讲一讲我现在用的键盘按键配置。

去掉了最上面的数字行。我相比 5x12 更喜欢 4x12 的布局,所以也更喜欢这样更精简的设计。

其实 Corne 包含了一系列键盘,布局都是一样的,主要是支持的键轴不太一样,有直接焊接的版本,有可以使用热拔插 socket 的版本,还有使用 Kailh 的巧克力键轴的版本,可以做出非常矮的键盘。所有 PCB 文件都是开源的,并且组织的很好,是非常不错的学习材料。

我是直接在 BoardSource 买的 kit,之所以对这个 kit 感兴趣,当然一方面是觉得好玩,同时也是想在自己设计 PCB 之前积累更多经验。在上一篇博客中介绍过的自己组装的 5x12 的键盘有一点让我比较在意的是微控制器是隐藏在按键下方,放在 PCB 的背面的,这样从外观上来说更加美观简洁,但是这同时增加了键盘的整体高度。所以看到像 Corne 这样的把微控制器放在 PCB 正面的设计就不禁很好奇这样可以让键盘的整体高度降低多少。

当然降低高度的方法还有一个就是不使用 Elite-C 之类的,而直接把微处理器和需要的电阻电容之类的元件焊到板子上,像 Planck 的 PCB 那样,占用的空间就很小,因为 Elite-C 其实自己本身就是一个小 PCB,预先焊好了 USB 接口和 MCU 需要的一些电子元件,只暴露出 IO 针脚来,这样做键盘之类的应用会容易不少,而且最主要的好处是非常方便人工焊接到键盘 PCB 上,反过来如果是采用单独的 MCU 的话,就需要做难度很高的芯片焊接,甚至有些芯片被设计来就是无法人工焊接的;如果不进行人工焊接,就需要在打印 PCB 的时候使用额外的自动焊 SMD 元件的服务,我也没有了解过,不知道是不是费用或者时间上会增加许多。

对分离式键盘感兴趣的另一个原因就是分离式键盘除了按列错开之外,两手的键盘可以分别有一个角度,是更符合我们手腕自然放松时的姿势的,并且分离式键盘可以让你家的猫坐在中间最重要的位置也不会影响键盘使用,总之在人体工程学方面有一些可以说的地方,具体到底有多大区别,这也是我想尝试的点。

有过上次的组装经验之后,这次对整个过程已经清楚很多了,拆开 kit 就发现 BoardSource 给我漏记了一些小零件,联系他们补寄的时候顺便也发现他们的库存的 Corne PCB 混杂了 V2 和 V3,于是让他们给我换了 V3 的 PCB。Corne 的 PCB 原本是一个很机智的设计:就是左边和右边使用的是同一块 PCB——打印两份,翻一面就可以用作另一边,这对于自己去找厂商小批量打印 PCB 尤其友好,因为通常都有至少 5 份之类的规定,翻面可用的话,就不会多出太多用不到的 PCB 了。当然要做这样的设计也有需要取舍的地方,因为键轴、微控制器等各种其他组件都不是左右对称的,所以 PCB 里的电路其实是要同时支持正面和反面,这不仅让内部电路布局非常复杂,而且有许多焊接点被排的非常近,大大增加了焊接难度,同时为了让正面和反面的微控制器的针脚错开,左右手最终微控制器的位置其实并不是完全对称的。所以在 Corne 最近的版本(包括 Corne Cherry V3、Corne Light 等)中都放弃了这个设计,而直接给出左右两边对称但不同的电路布局。

Corne kit:基板、定位板、底板;Elite-C、二极管、音频线等。

有一个小问题是 Corne 的官方组装指南是日文版的,虽然网上有一些第三方不是特别详细的组织指南,但是 V3 由于比较新,还是得看官方指南。想不到我学的日文终于能在动漫之外的其他地方用到了。不过其实如果有一些组装键盘的经验的话,只看配图也基本上能明白一个大概,因为用的基本元件也都差不多。最大的一个区别在于这次的二极管不是 through hole 的,而是 SMD 元件,非常小,也没有针脚固定(见下图),所以主要是 N 的焊接难度增加了。焊接技巧是要先涂点 flux(助溶剂),在一个 pad 上先加一点焊锡,然后用镊子夹着二极管顶着已经有的焊锡,把它融掉,同时迅速摆好位置。总之一只手拿焊枪一只手拿焊锡还有一只手拿镊子,感觉如果只有一个人的话是相当困难的操作。另外助溶剂如果涂多了板子上会有点黏黏的,可以用酒精擦拭清洗。

细小的柱状 SMD 二极管,没有针脚滚来滚去,比较难焊。

一如既往组装完成之后是有一些问题的,虽然这次我们已经有相当多的经验和知识,但是碰到的是新的问题:有几个键没有反应。由于每一行和每一列都至少有一个键是正常工作的,说明整体电路没有诸如短路之类的大问题。我们做了一些基本检测,比如人工短路按键两端测试没有反应可以基本排除是键轴的问题,用万用表测试二极管保证二极管不是坏的。剩下就得从电路入手了,键盘的基本矩阵电路布局上次已经介绍过了,如下图所示,如果按键 SW3 没有反应,那么说明从 A 到 D 的通路哪里有断掉了,我们短路了 AB 没有反应,CD 之间的通路也测出来没有问题,那么问题出在 BC 之间?在 N 的建议下直接短路了 BD,然后按下按键发现有反应,那么就确定了问题出在 BC 之间,但是麻烦的是 BC 之间的通路是在 PCB 板里的电路定义的,难道是 PCB 坏了?

如果真是那样还真有些头疼,不过幸运的是还有其他一些可能,比如电路从元件到 PCB 内部电路之间的焊锡连接如果不通的话也会有同样的症状。幸运的是事实却是如此,在 Kailh hotswap socket 和二极管的针脚处都增加焊锡加固之后,问题就解决了。虽然最后并没有完全确定问题是在二者中的哪一个那里,也许是焊新的二极管不太习惯导致的一点失误吧。

完成之后就可以写入固件开始使用了,Corne 两边都各有一个微控制器,我的理解是按键解释是在主控制器(左边)完成的,所以如果一开始两边都写入了一个默认的 Corne 固件能保证通讯顺畅的话,之后如果只是修改 keymap 可以只更新主控制器的固件。但是如果有修改 OLED 显示代码的话,则需要在两边都分别写入,虽然使用的是同一个固件,但在运行时会互相协商判断谁是主谁是次,保险起见我在写入固件的时候并没有把两边连接起来。还有这个音频连接似乎并不是可以热拔插的,有可能会烧坏电路,所以需要把 USB 连线断开之后再拔插音频连线。

kit 自带的音频线很长,于是我自己买了一根很短的拐角头线,这样让我可以把左右靠得很近,不过似乎也是习惯问题,一两天以后我就比较习惯两手完全分开的状态了。不过分得太开也不太好, 那样鼠标就又没有地方放了(还记得最初开始用小键盘的理由是为了给鼠标腾出更多的空间吗?),当然也是可以考虑把一个苹果的 Magic Trackpad 放在中间使用的。至于两手分开以及有角度之后是否使用起来对手腕负担更小更舒服呢?我也说不准,至少(在一两天的磨合期之后)没有更不舒服,具体效果如何可能需要大规模对比实验和医学上的观察才能真正确定下来。

另一个 Corne 的好玩的地方在于两边各提供了一个 OLED 屏幕,现实什么内容是完全可以定制的,默认一边显示一个 logo,另一边显示你最近输入的按键(输入密码的噩梦),我把它们改成了显示 Shift 之类的修饰键的状态和当前的 Layer 状态,在文末在介绍如何定制,这里只放一个小动画显示符号、数字和 navigation layer 的状态切换。

Reviung41 and Keyboard Mounting Styles

Reviung 是一个 id 叫 gtips 的日本人设计的一系列键盘,其中可能最有名的是 Reviung39(定制键盘中末尾的数字经常用来指按键的数量),底部只有三个按钮,有点不够用,于是后来又推出了 Reviung41,增加了两个键,现在底部变成了五个键,基本上就完全和 Corne 的布局一样了(后者左右各有一个空格键)。和 Corne 相比坏处是不是分离式的,所以两边的距离和角度都是不可调节的,不过我觉得这个基本上不是问题,除非你是会把分离式键盘放得非常开,到中间可以放一只猫一个触控板的程度,否则 Reviung41 默认的角度和距离其实是挺舒服的。和 Corne 相比好处也是一样的——不是分离式:这在需要经常移动的时候尤其明显,分离式键盘基本上无法单手拿起来,所以如果经常要移动笔记本和键盘的话,就有点略不方便。

当然整体来说我觉得 Corne 和 Reviung41 还是相似大于区别的,我几乎是在下单了 Corne 之后立刻又下单了 Reviung41 是因为后者在开源的仓库里提供了非常丰富的中间板的源文件。在讲对中间板感兴趣的原因之前需要先解释一下键盘的基本构造。网上有一篇文章介绍得比较详细,我这里也不多说了,一般来讲键盘的基本骨架由定位板(top plate)、基板(或电路板、PCB)、和外壳组成。怎样把这些部分组装在一起就是设计上的细节了,不同的组装方式可能对手感、声音之类的会有影响,网上有一张图解释了几种常见的组装结构:

当然这些主要都是比较高端的定制键盘的组装结构,因为外壳是一个三维的结构,用金属之类的原料做出来是一个相对比较复杂的工艺,即使通过 Group Buy 累积大量订单的情况下通常也至少要一两百的价格,由于模具准备之类的工作,通常如果你只想做少数几个的话,可能成本会高出天际或者厂家直接不愿意做。所以如果错过 Group Buy 的话就比较难搞到手,自己即使有三维设计的本领,想要把设计变成现实通常也必须通过 Group Buy 的方式来实现,总之是一项非常繁重的工作。

相比起来,如果只是在一块板子上做切割做出特定的形状,就是容易得多的事情,网上有很多服务(我听得比较多的有 ponokolaserboost)可以提供各种金属、塑料、木板之类的激光切割,也都接受数量很小的订单。到这里我终于意识到为什么前些年 3D 打印开始普及是一件大事了,这对于各种想要设计和实现各种原型磨具的爱好者来说简直就是升维福音。不过似乎现在 3D 打印出来的东西都还比较粗糙(至少我在网上看到大家展示的自己打印的一些东西大都是这样),暂时没有让我特别感兴趣。

总而言之由于三维外壳制造困难,定制键盘社区里许多对高端键盘不是那么执着(或者厌倦了 Group Buy 的漫长时间线)许多人就之间采用所谓“三明治组装”的方式来做定制键盘,也称作 EOTW (Easy on the Wallet) 组装方式。具体来说有点像上图中的第一个 Tray mount,不过底部的外壳有一个平面底板代替。由于所有的结构都是可以可以通过平板切割的方式构造出来的,所以相对比较容易自己收集部件,除了可以切割金属或者塑料之外,甚至还可以直接通过打印 PCB 的方式来做定位板和底板,因为 PCB 板制造过程也支持各种切割,并且它的用料复合玻璃纤维 FR-4 其实是比 Acrylic 塑料更结实的,所有只要打印一个没有内嵌任何电路的电路板就可以当底板或者定位板使用。事实上不少第三方不需要通过 Group Buy 就直接可以购买的键盘 DIY kit 都是 FR-4 的三块板的 EOTW 组装方式,包括我之前组装的 5x12 和这次的 Corne 和 Reviung41。

当然这里还可以更简化,比如其实定位板并不一定是必须的(见上图的 Plateless mount),但是定位板能够给键轴体提供更多的固定作用,有说法是不同定位板的材质由于弹性不同会给按键手感带来很大的区别,不过我并没有特别研究过这个,总之大部分情况下定位板还是有的。至于底板,由于 PCB 地步通常有不少电子元件,或者至少有键轴的针脚之类的,一般加一个底板会比较好,当然如果不需要把键盘放在腿上用不用担心扎到自己的话,应该直接在 PCB 版底部合适的地方贴上几个 rubber feet 支撑一下也能正常当桌面键盘使用了。比如 keyseebee 键盘(如其名 KeyCB)就同时省略了定位板和底板。相比起来 Corne Light V2 省略硬质底板,而用一片软的切割过的 form 材料直接贴到 PCB 底部的做法更让我感兴趣,省略了 spacer、螺丝,降低了键盘高度,还自带一个软的底部,也不需要贴 rubber feet 了,不知道是不是在声音上也会自动有所改善。当然感觉 form 的话自己切割不知道会不会搞得比较不规则,而且当做最外层不知道会不会比较容易沾灰尘之类的。

左:Reviung41 加 Acrylic 半透明中间层;右:Corne Cherry EOTW 中空组装。

总之回到 EOTW 组装方案上,从之前的示意图可以看到主要的组装点是用螺丝把底板和基板固定在一起,也有反过来在 PCB 板上打比较大的空,让螺丝(spacer)穿过 PCB 板和定位板固定的方案。但两者有一个共同点就是都把基板和定位板当做一个整体来对待。这在非热拔插键轴的情况下是很合理的,因为键轴针脚上的焊锡会把两块板子固定在一起。但是这几年热拔插的键轴组装方式越来越流行,这种处理方式就不是很理想了,因为键轴把出来的话,两块板子就分开了,会导致其中一块板子没有固定。即使对于不是特别经常要换键轴的玩家,也会有一些小问题,比如如果在移动的过程中比较用力地捏了其中一边,或者平时按键就是比较大力的那种,有可能会让两个板不再平行,除了不太美观之外,极端情况下可能会导致另一端翘起来键轴脱落之类的。

最简单的解决方案是在底板和基板、基板和定位板之间都加合适的孔各自用 spacer 分别固定,这个在基板上需要钻的孔的数量会加倍,而且原来底板和定位板之间用一个 7~8 毫米的 spacer 就可以了,现在需要分别用两个 3 毫米左右的 spacer,在尝试自己采购零件之后发现像螺丝和 spacer 之类的零件原来并不如想象的那么容易搞到,特别是对于 3 毫米之类的很短的 spacer 来说。总之现在很多 kit 都没有尝试解决这个问题,不知道是历史原因设计没有及时修改还是各种解决方案都没有特别理想。不过 Reviung41 在日本销售的 kit 里提供了 5 块板子,多余的两块板子分别是 3mm 的 Acrylic 塑料板,分别放在底板和基板以及基板和定位板中间,各自都有合适的 cutout 给每一层的元件留出空间,同时又起到支撑的作用。类似的多层 Acrylic 叠加的办法在其他一些 kit 里有时候也会见到(例如 Discipline),甚至还可以叠加的方式做出带斜面的底板。在 BoardSource 上买到的 kit 虽然只有普通 EOTW 的三块板,但是开源仓库里可以下载到所有板子的设计文件,于是我自己把文件发到 Ponoko 去做了切割,一方面也是熟悉一下各种工艺的流程之类的,万一我之后自己想搞一些玩意也可以有一点概念。效果整体来说还是不错的,见上图加了额外中间板的 Reviung41 和 Corne 的对比。其实我还切割了一个 1.5mm 的底板,但是 1.5mm 对于 Acrylic 来说似乎有点太薄了,而且那个源文件里还有比较大面积的 engraving,最后得到的板子甚至有点弯曲,于是我就还是用 FR-4 的底板,也算是一个经验教训。

上图左边是用 Ponoko 的激光切割的 3mm Acrylic 板,从下单到收到大概是十天左右,Ponoko 似乎就是在湾区,所以快递上应该没有花太久的时间。收到的时候两边还贴着保护膜,看着有点像木板,撕掉保护膜挖出多余的料简单清洗之后如右图。

更新:解决基板和定位板的支撑问题还有另一个不需要改变已有的设计的办法就是使用大的短的 spacer 套小的长的 spacer,不过这个办法有可能会碰到 clearance 的问题,因为基板底部有 Kailh hotswap socket,而顶部则有键轴轴体,原来钻孔的地方不一定能够有足够的空间来放直径更大的 spacer。不过最近在网上看到有人做了类似的尝试,于是我也决定在 Corne 上试一下。于是我买了一些包含不同尺寸的 Nylon Flat Washer,小尺寸基本上都是 1mm 厚,试了以后发现 corne 板子上的 M2 spacer 的外径需要用 M4 内径的 washer 才能 fit。然后我把三个 washer 叠起来基本上刚好够支撑的高度。如下图所示,取决于键盘的设计,有些地方(青色箭头)直接放上 washer 就可以,但是红色箭头处由于 hotswap socket 挡着,就很难 fit,不过好处是 Nylon 的 flat washer 比较容易修剪,用剪刀就可以剪,不过如果有右边那种剪电线的钳子会更容易操作(碎片飞溅最好戴个眼镜保护)。如右图所示,基板的正面(也就是定位板的背面)是更难 fit 的,因为方块挖空的地方都是给键轴轴体留的空间,不能堵住,所以要把垫片剪得非常小,虽然麻烦了一点,不过最后也都成功 fit 了,增加支撑之后三块板都更稳定了,而且这个办法比制作专门的 Acrylic 中间层要实惠很多倍了。

Reviung41 Build Log

Reviung41 的组装指南也是日文的,不过确实是超级详细,中间 LED 灯的部分花了大量篇幅来讲解。我本来是对键盘花哨的 RGB 光特别不感冒的,不过 Reviung41 没有 OLED 屏幕,所以我想如果有 LED 灯的话是不是可以用 LED 的颜色来指示一下 layer 之类的,所以也买了 LED 灯。事实证明这是这次组装的新挑战。下图是 LED 灯与硬币的对比,不仅很小,而且有四个针脚需要对齐焊接,也没有明显凸出来的针脚。而且这个是 WS2812B 似乎是比较容易焊接的了,据组装指南上说 Reviung39 用的是 SK6812MINI 更难焊。

其实仅仅从大小来说至少不比 SMD 的二极管小,但是 LED 灯的难点在于它不怎么耐热,需要迅速焊接好,否则很容易烧坏,并且还需要使用 270℃ 左右的温度,比平时焊接要低很多。不知道是我们的焊枪温度指示不是特别准还是确实就是这样,在这个温度下几乎是勉强能融化焊锡,非常难以操作。在做过许多次失败的尝试之后我们直接放弃了,开到了正常的温度,之后由于有之前焊 SMD 二极管的经验,就容易操作多了,不过有没有因为温度太高而烧坏 LED 就没有谱了,反正 LED 对我们来说不是必须的。剩余的步骤就和 Corne 也差不太多,由于只有一个 Elite-C 也不需要两边连接,所以其实更简单,最后买到的 kit 在安装 Elite-C 的保护罩的时候似乎缺少合适的 spacer,还好我在这阵子已经开始自己在网上购买一些不同类型的 M2 spacer 了,找到了合适的安装上。

这次组装……当然也一如既往地没有一帆风顺。主要有如下问题:我自己打印的 Acrylic 板的 cut 似乎在空格键的 stablizer 那里不够宽,合不上。仔细看了一下原来板是根据 Cherry 的 Clip in 的 stablizer 来做的,而我用的 Durock screw in 的 stablizer 在螺丝那里要宽一些。还好我刚好有多余的 2U cherry stablizer,换上就好了。另一个问题是有两个按键没有反应,用万用表调试了一下发现有一个二极管似乎是坏的,把它取下来(SMD 元件 desolder 似乎使用 Silder Wick 会比较容易)换一个新的就好了;另一个键是发现它的二极管有一头忘了焊了😂,焊上就好了。最严重的问题还是 LED,除了一号和二号,其他的都不亮,顿时特别受打击,难道是剩下的九个全烧坏了?想有没有什么办法测量 LED 是不是坏掉的,似乎也不是那么简单,因为这个 RGB LED 并不是通电就亮的那种,而是有 data 输入可以控制 RGB 值的。紧张了一阵之后 N 表示这个问题出得太蹊跷了,而且组装指南上明确地写明先焊第一个,测试亮之后再焊第二个,按这样的顺序取焊,一定有什么深意,莫非 LED 的连接方式是其中有一个坏掉的话剩下的就都不亮?于是我去网上查了一下 RGB LED 灯的连接方式,果真如此!于是一个简单的调试方式就是用连线直接跳过某些段的线路,结果我们把 LED2 的输出直接接到 LED3 的输入的时候所有的灯都亮起来了。

最激动人心的莫过于是看到 LED 灯一个都没有坏,可见正常温度焊也没有那么容易坏,只要操作够迅速。目前的情况应该是 LED2 的输出针脚或者 LED3 的输入针脚中的一个跟 PCB 接触不太好,补了一些焊锡重新焊过之后就一切正常了。要使用 RGB LED 来指示修饰键和 Layer 的状态可以参见 QMK 的 RGB Lighting 一节的文档,只要打开一个编译开关即可。

Colemak DHm

细心的小朋友可能已经注意到本文一开始的照片里的键盘已经不是 QWER 的排布了,那是因为我终于没忍住开始尝试 Colemak 键盘布局了,确切地讲,是 Colemak-DHm,由于我在那一套键帽里只有 F 和 J 有凸起,所以处于寻找键位方便仍然放在原来的位置,不过按键是已经完全按 Colemak-DHm 定义过了。

Colemak 是一个针对英文优化过的键盘布局,我想可能我们也可以做自己的优化,比如先定义好各个按键容易按的程度,然后通过优化和搜索,判断怎样的布局让你“更容易”打出给定的文本数据集,这里“更容易”可以是每个按键的容易程度,但是体验了一把“重新学习打字”的过程之后我发现其实我们打字很少是一个字母一个字母的按的,就像弹钢琴我们会看到音阶、分解和弦之类的构成一样,打字也会有很多诸如 ion、ear、bility、之类的 n-gram 是比较高频出现的,在打字熟练的过程中大脑会开始以这些 n-gram 为单元进行优化和调度,提前计划好手指的移动和转移路径。所以键盘布局应该至少也要把常见的 2-gram、3-gram 之类的考虑进去,有时候两个按键各自都是比较好按的,但是放在一起就有点别扭了(比如使用同一个手指,但是是在相反的方向上)。总之定义一个键盘布局还是有挺多东西要考虑的,不过最大的问题还是键盘帽的问题。像 Colemak 这几种常见的非标准布局已经相对比较普及了,所以还是能找到一些键帽套装支持他们,但是如果是自己搞的布局的话,可能就只能用统一形状的键帽或者甚至是空白键帽了。下图是用 kle-render 渲染出来的 Colemak-DHm 布局的字母排布,图中带颜色背景的键是我认为我(在几乎完全不需要动手腕的情况下)最容易按到的键,我在定义数字、符号等 Layer 的时候也会参考这个偏好。可以看到比较常用的字母(包括所有元音字母)都放在了比较好按的位置。

从 QWER 切换到 Colemak 比从标准键盘切换到正交键盘还是要更费力一些的,不过也没有到难以企及的地步,而且观察自己重新学习打字的过程也挺好玩,还能帮忙纠正一些不好的习惯。每天练习一点时间,大概三天就能到达 30 英文单词每分的速度,N 基本上每天只练习 10 分钟也在一周左右达到了 30 WPM。我是在 10 天之内达到了 50 WPM 的速度,再到后面上升速度就慢很多了,我现在差不多是切换过来 40 天左右,大概是 60+ WPM 的样子,但是其实平时工作和写代码已经基本没有问题了,应该再过一段时间就能完全习惯。

切换 Colemak 除了键帽比较难找之外,还需要适应的几个小问题是大都跟肌肉记忆有关。一个是常用的快捷键,比如 V 的位置变了,所以 Cmd+V 自然也需要按不同的键,这个对我来说是很快就适应了。比较费时的是中文输入,因为我用的是双拼输入,原本就是一个字母到不同韵母之间的映射,之前打习惯了之后其实记住的是每个韵母在键盘上的位置,而不是对应到哪个字母,所以其实这里是需要重新记忆一下的,不过整体也不是大问题(本文就是用双拼加 Colemak 打的)。再就是和 VIM 的兼容性的问题,VIM 最标志性的按键应该就是 HJKL 来移动方向了,换成 Colemak 之后这几个键的位置就不一样了,网上有一些解决方案是直接在 VIM 里把方向重新映射为 Colemak 改过之后对应的这四个键,但是这样无疑会引入新的问题,因为这几个键在 VIM 里可能原本也有其他的用途。而且我觉得自己现在大部分时候其实并不是在用 VIM,而是用一些其他有 VIM 快捷键的编辑器或者系统,有时不一定能定制。于是网上另一些人干脆就继续用 HJKL,只是按起来没有原来方便了,不过对于 Colemak-DHm 来说这几个键其实都还在右手食指的管辖范围内,所以不是特别糟糕。后来我干脆给自己的键盘布局增加了一个单独的“导航”层,把原来 HJKL 键的位置也就是现在的 MNEI 键直接映射成了方向键。

刚刚组装完键盘的凌乱的桌面旁边的 Colemak 布局打字测试大比拼。

最后一个问题也是牵涉到兼容性的:是否要直接放弃 QWER 布局?似乎没有这个必要,在许多地方(比如自己的笔记本上,或者手机上之类的)都会碰到 QWER 布局,如果能同时保持这两种布局的熟练程度的话就可以无缝切换了。网上确实有不少人是这么做的,通常加一点易于区分的 hint 会让切换更容易,比如在打 Colemak 的时候使用正交键盘,而 QWER 的时候使用按行错开的标准键盘;或者两种布局分别用左右手的拇指来按空格。我目前的情况是手机上的 QWER 键盘基本没有受到影响,但是实体的 QWER 键盘基本处于不可用的状态。我是打算等 Colemak 熟练到完全不会打错之后再把 QWER 捡起来。N 的情况完全不一样,她才刚开始用 Colemak 一周多,Colemak 到 30~40 WPM,但同时对 QWER 布局的输入完全没有任何影响,而且我注意到她好像不自觉地就在两种布局时用不同的拇指来按空格键了,真是很神奇。

Planck Layout

在这里介绍一下我(略微更新过的)键盘布局。现在我有好几个不同形状的键盘了,但是其实他们之间的区别并没有特别大,差不多都是 3x12 的正交矩阵排布,再加上最下面一行的空格、层切换和修饰键。有的键盘可能会多几个按键,但是我基本上可以统一使用同一个布局。

其实定制键盘的一大好处就是按键是完全可以定制的,最常用的定制键盘固件 QMK 采样一种比较粗暴的代码组织方式:把所有支持的键盘的代码都放在自己的主仓库中,所以在 QMK 代码的 keyboards 目录 下可以找到非常多不同的键盘,其中许多键盘的形状和布局都可以在 QMK Configurator 的 web 界面浏览到。还有更多用户定制的布局,例如 keyboards/planck/keymaps 下面就有几十个不同的用户自己的布局。还有一个最近很流行的叫 miryoku 的布局,支持各种正交和分离式键盘。总之如果要定制自己的布局的话,可供参考的资源还是很多的。

下面介绍一下我自己的布局,也仅供参考。我的布局定义有几个参考原则:

  1. 减少手腕移动:参考我在上面给出的正交键盘(去掉大拇指一排)的按键里最容易按到的键,我会尽量把按键映射到这些键里。比如我把数字键映射到了中间排,而不是网上比较常见的最上排。
  2. 宁缺毋滥:我的目的并不是要把完整键盘上的所有键都映射出来,比如 F1、F2、Scroll Lock 之类的我就直接略过不管了。此外基于第一条原则,我也不会把 Layer 里所有的键都排满。
  3. 尽量不乱动字母键:网上有许多布局(例如刚才提到的 miryoku)的思路跟这个完全相反,他们的理由是既然 home row 的键那么好按,那么就应该更多加利用,从而减轻小指和拇指的负担,于是通过 tap-hold 的方式把许多字母键变成修饰键或者层切换键。比如我让 s 键在 tap 的时候是字母键,但是在按住不放的时候就是 Cmd 键。这看起来很方便,但是实际使用起来可能需要经过许多参数微调(比如 tap 和 hold 的时间判别阈值和其他一些特殊规则),比如如果你打字很快,在输入 ask 之类的词的时候,可能你 s 键还没放开的时候 k 已经按下了,结果有可能会得到 Cmd+k 而不是 sk。

基本层就是 Colemak 的正常字母布局,左边三个键分别是 Tab、ESC 和 Shift,右边三个则是退格、引号和回车。红色的键表示有 Tap-Hold 功能,左下角表示 Hold 时的键,例如 Esc 键 Hold 住是切换到第三层,这是我的 Navigation 层,之前原本是 Hold 住是 Ctrl 功能,但是后来这个位置留给了更重要的 Navi 层切换,于是把 Ctrl 的 Hold 放到了右边引号处。回车 Hold 时有 Shift 功能,因为我不太用 Caps Lock 键,所以需要两边都有 Shift。底部五个键分别是 Cmd、向下(切换到 Layer 1)、空格、向上(切换到 Layer 2)和 Alt。Cmd 是在 Mac 下最常用的修饰键,其实和 Cmd 搭配的大部分字母(诸如 ZXCVTPWQ 等等)都在左边,所以把 Cmd 放在右边让两手分工更合适一些,但是我发现按 Cmd 相关的许多快捷键(例如复制粘贴)经常是右手在操控鼠标之类的的时候,所以把 Cmd 放在左边可以单手完成按键似乎更合适。

向下(第一层)主要是数字,我把数字放在第二行方便输入,同时把 Base 层的一下键如小数点、逗号、x 键之类的也放在这里,有时候我要输入数值 0x123.56 之类的可以一直按着向下键,更方便一些。另外在第一层的时候右下的层切换按钮会变成第四层,类似地在第二层我会把左下的层切换定义为到第四层,这样我在同时按下向下和向上的层切换按钮的时候就可以切换到第四层。第四层主要放一些不太常用的功能,例如键盘 reset、RGB 背光调整,或者一些复杂的快捷键宏(例如 Mac 下的截屏)。在左右手三、四指上方各放了一个键用来输入括号和加减号,具体摆法和上一次介绍的稍微有所调整。

和向下层对称的是向上层,基本上是向下层的 Shift 版,如下图各个键的右上角标识所示,虽然都可以用向下层加 Shift 的方式按出来,但是那样按起来太费力了,所以按照惯例有单独的一层。另外在这一层我还多修改了两个键:左边的 Shift 变成 Caps Lock,退格变成(向后)删除键。

Navigation 层主要就是原来 VIM 的 HJKL 四个键变成了方向键,不过好处是现在不止在 VIM,而是在任何地方都能使用它来移动了。此外我还在左边加了一些 modifier 键,比如移动的时候如果想同时按住 Shift 选择的话,去按原来的 Shift 键就非常别扭,但是现在可以左手小指按住层切换键,食指就可以轻松地按只有这一层里才有的另一个 Shift 键,右手移动即可。另外这一层我还加了一个跳到第五层的按键,目前放在一个并没有很好按的位置,因为我也没有确定是否要留下这一层,第五层是鼠标层,基本上和第四层的布局是一样的,只是可以让光标和滚轮上下左右移动,用起来估计没有鼠标方便,但是也许可以偶尔临时用一下(特别是滚轮),之后看是否真的好用再决定是否留下吧。

QMK 提供的 Web 界面的 QMK Configurator 不仅可以浏览已有的 keymap,也可以做自己的定制,然后直接在线编译,即可下载到可以使用 QMK Toolbox 写到板子里的固件文件。同时可以把定制的 keymap 下载成 json 文件,如果以后还需要做修改,只要直接上传已有的 json 文件即可,不用从头开始。如果要对 QMK 做一些更深层次的修改,就需要修改源文件,当然可以直接手写编辑 keymap.c 来定义自己的 keymap,但更友好的做法是直接用 qmk json2c 命令把导出的 json 文件转化为一段 C 代码,复制到自己的 keymap.c 中即可。

由于不同的键盘仍然需要不同的 json 文件,如果修改键盘布局就每个都要修改,还是有点麻烦。好在我用的几个键盘 (Planck、Corne、Reviung41 甚至是 5x12) 的布局都是大同小异。于是我只维护一个基本的 4x12 格子 keymap,然后用一个简单的脚本来把它转换为不同键盘对应的 json。

OLED Customization

最后简单介绍一下 OLED 显示的定制。许多分离式键盘——特别是那些把 Pro Micro 或者 Elite-C 焊在基板正面的 kit 很多都可以添加一个 OLED 显示模块,因为 OLED 模块的大小基本上和 Pro Micro 差不多,所以刚好可以放在上面。说起 OLED,我一开始想到的是 iPhone 的超高清屏幕,但是我们在键盘里用的这个 OLED 显然不是那么高级的玩意,它价格在 5 美元以下,而且分辨率只有 128x32,别说颜色,甚至连灰度也没有,只能显示黑白像素,不过键盘 Controller 里值得显示的信息也非常有限,这个简单的模块其实更适合定制玩一玩。

Corne 自己的固件自带的功能是显示最近的按键、层信息和修饰键信息,都比较有用,不过是直接用文本显示的,比较小,再加上 OLED 屏幕是旋转 90° 竖直安装的,很难看清楚。于是我把两边的 OLED 都利用起来,把信息用旋转之后的比较大的图标显示出来。另外通过时间计算还能显示一些动画之类的。网上有人做了诸如一个猫的动画之类的。我的模块在之前给了一个短视频展示,这里还有一个长一点的 demo。

OLED 的显示主要是使用 QMK 提供的 API,虽然也有写 raw pixel 的 API,但是最常用的还是打印字符串的 API,用 oled_write_ln_P() 之类的函数可以输出文本信息,在一些比较老的 OLED code 里可能会看到一些模块初始化之类的代码,不过现在这些 QMK 都包装好了,只需要在 rules.mk 里加上 OLED_DRIVER_ENABLE = yes 就可以使用 API 了。

用字符串 API 显示图标的方法是使用定制字体文件。QMK 自带了一个默认的字体文件,可以正常显示 ASCII 码里的字符,但是我们可以通过使用自己的字体文件显示额外的内容。虽然说是“字体”,但是也完全没有我们平时用的字体那么复杂。由于 OLED 只能显示黑白像素,所以字体信息其实就是一个二进制位图,如下图所示,每个 6x8 的方格表示一个字符,前面四行每行 32 个字符其实就对应了 0 ~ 127 的 ASCII 码,API 在打印字符的时候其实就把每个字符对应的方格里的像素拿出来显示在 OLED 屏对应的地方。

虽然 API 里用的是 char 类型,但是仔细看 QMK 里的 OLED driver 代码实现的话可以看到 char 最终会被强制转化为 uint8_t 来处理,所以我们实际上能使用 0 ~ 255 的字符,在额外的四行里就可以画一些自己想要显示的图标,然后通过打印对应的“字符”来显示它们。当然如果你确定你的 OLED 里不需要输出文本的话,甚至可以把整个字体文件全改掉也没有关系,或者你可以直接通过 oled_write_raw() 之类的函数来写入像素,这样(除了你的微控制器的内存)就没有任何限制了。不过我们这里不需要显示过于复杂的东西,所以仍然使用字符 API,例如我可以通过下面的代码来显示字体里的 QMK 的 Logo(那个中间有个 Ψ 字的东西):

  1. void render_qmk_logo(void) {
  2. // this assumes the OLED is rotated vertically, 5 char wide
  3. static const char PROGMEM font_logo[] = {
  4. ' ', 0x8E, 0x8F, 0x90, 0x91,
  5. ' ', 0xAE, 0xAF, 0xB0, 0xB1,
  6. ' ', 0xCE, 0xCF, 0xD0, 0xD1, 0,
  7. };
  8. oled_set_cursor(0, 0);
  9. oled_write_ln_P(font_logo, false);
  10. }

注意 0x8E 这些 code 其实就是 Logo 左上角的“字符”在字体位图里的 index,末尾的 0 是 C 语言里用来表示字符串结尾的。要显示简单的动画也很简单,可以用类似这样的代码来得到一个当前帧数:

  1. int get_frame_number(int total_time, int n_frames) {
  2. return (timer_read() % total_time) / (total_time / n_frames);
  3. }

然后画出对应的帧数即可,具体的例子可以参考我的 Corne 固件代码里的 oled.c 文件。有一个非常简单但是已经比较酷的动画就是可以画一个闪烁的光标表示等待输入。不过我发现在正常待机状态下如果现实动画的话,键盘长时间没有输入 OLED 模块好像也不会自动进入待机关闭状态,也许是通过判断内容是否有变化来决定是否休眠的,所以我只在 Layer 切换的时候显示了一点动画。

最后一个问题就是如何修改和载入字体文件了。所谓的字体文件其实就是一个 C 文件里面定义了一个叫做 font 的字节数组,把位图里的所有数据用十六进制常量表示出来:

  1. const unsigned char font[] PROGMEM = {
  2. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  3. 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00,
  4. // ...
  5. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  6. };

所有你可以用任意的图片编辑软件编辑一个合适大小的位图,然后用 image2cpp 之类的工具把图片数据转化为 C 里的字节常量即可。用自己的图片编辑软件的好处是编辑功能比较强大(复制粘贴移动之类的),另一个选项是使用 helixfonteditor,这是一个简易的在线编辑工具,直接上传我的代码里的(或者 QMK 仓库里的其它的)glcdfont.c 就可以开始编辑,编辑完即可下载更新的 glcdfont.c 文件。这个在线编辑页面显示出了每个字符的边界,所以比较不容易搞错,不过编辑功能比较基本,鼠标左键涂黑一个像素,右键清空一个像素,没有其他功能了,比如如果想把一片区域整体移动一个像素的话似乎就得人肉重画。拿到自己定制的 glcdfont.c 之后,在自己的 keymap 的 config.h 里把 OLED_FONT_H 指向这个文件即可:

#define OLED_FONT_H "keyboards/crkbd/keymaps/crkbd-kid/glcdfont.c"

具体显示什么好玩的就看自己的想象力啦 😃。