Keeb
一些 Essentials
对于键盘来说,从用户的角度,是由按键组成的(编码器/虚拟按键等,暂不考虑)。
一个一个的按键,组成了键盘的布局,用户根据布局操作每一个按键。 因此,layout是最上层的概念。对于软件来说,layout包含如下特性:
- layout共有多少行、列
- layout的每一个位置和PCB中的矩阵的对应关系,哪些位置有按键,哪些没有。
- layout存的是键位的设置,而每个键位的具体功能,则存在和layout对应的keymap中。
在Keymap中,存储的是每个按键的按下后的具体功能 Action 。一个keymap可以有多个layer,keymap和layer的关系,可以参考 https://docs.qmk.fm/#/keymap 。
在实际用户使用的时候,首先是要获取用户触发的键位 position ,然后判断用户的 TriggerType(触发方式)。 对于键盘来说,每一个按键可以有如下的触发方式:
- 按下/抬起:最普通的触发方式
- tap:把快速按下+抬起组合起来,看做是一个动作。只有完成了整个的tap动作,才会触发。tap一般都有一个时间上限,在时间上限内完成 按下+抬起,可以识别为tap
- tapN:连续N次tap
- hold:长按,有一个最低时间。
- NO:没有动作,默认的
然后,根据对应 keymap + position 里面存储的 Action,再加上 TriggerType,就能得到键盘最终执行的动作。
即 Position + TriggerType + Action = What's executed by keyboard(aka KeyboardAction).
然后,键盘 dispatch 所有的 KeyboardAction,去执行相关操作。
Definitions
-
keycode:键码
- 键码应该有 2 套:
- 系统支持的键码
- 内部的键码,包含系统支持键码 + 内部功能(比如切层、RGB、音频控制等等)
- 键码应该有 2 套:
-
layout:布局
- 需要支持KLE
- 要点:键位、PCB矩阵位置、形状 & 角度
- layout需要和具体的键位position绑定。然后,每个键位有X种触发方式,每一种触发方式有Y种功能。
-
matrix:PCB矩阵,和layout存在有限的对应
-
layer:层 QMK中,一共支持32层,可以同时激活多个层,多个层同时激活的时候,会从高往低逐个扫描,如果是KC_TRANS,就进到低层,直到在某层有一个有效的按键。支持如下切层功能:
- DF(layer): 设置默认层,默认层默认一直是激活状态。。默认层一般都是第0层,也就是最下面的一层
- MO(layer): 临时激活某一层,比如MO(1)就是临时激活第1层,松开这个按键的时候失效
- LM(layer, mod): 也是临时激活某层,区别是LM自带某个modifier(不用手再去按了)
- LT(layer, kc): 双功能,长按是激活某一层,单击是触发对应的keycode
- OSL(layer): 按一下临时激活某层,激活状态在下次按键失效。和MO(layer)的区别就是,MO(layer)需要保持按下激活某一层,而OSL(layer)是一次性的,只对下一个按键有效
- TG(layer): 切换某层的激活状态。上面的都是临时激活层,而TG是永久切换层的激活状态(开 -> 关/关 -> 开)
- TO(layer): 激活某一层,关闭其他所有层。这个在按下的那一刻起就生效了。
- TT(layer): 按下临时激活某层(和MO一样),但是增加了一个功能是,如果连续单击TT,则可以把这一层永久激活或关闭(相当于TG)。换句话说,TT是双功能,等于MO(按下) + TG(多击)。多击次数可以通过
TAPPING_TOGGLE
设置,如在QMK中,设置#define TAPPING_TOGGLE 2
,就是把TT设置成双击激活。
-
macro:宏
-
action:键盘的动作 除了基础的发送键码之外,键盘的按键还有其他很多功能,如:
- 层操作:临时切层/激活&失活某层/层+modifier/层的tap触发
- modifier
- tap
- 媒体控制(播放、暂停、音量)
- 系统控制(关机) 这些功能并不能被键盘的keycode覆盖,统称为 keyboard action
另外,再做一层抽象:人操作键盘有几种方式:
- 按下/抬起:最正常的方式,按下和抬起分别算
- tap:也就是按下 + 抬起触发
- hold:长按
- 连续tap:qmk中的tap dance
- 组合键:同时按下多个按键,可以是 modifier + key,也可以是key + key
在上面的这些,可以理解成是human action
-
debounce
-
协议层:支持via、vial
-
驱动层:trait for GPIO、LED、RGB、Encoder等等
-
tools:快捷生成、快捷接入等
-
cli:命令行工具
Keycode
System keycode
首先是系统接受的键码,这些键码是国际标准定义好的,可以参见QMK的文档。
tap key: 按一下就触发一次
Layer
QMK一共支持32层,层的操作上面有写。在具体实现上,
- 由于每层都是独立的,因此层的开启和关闭,主要使用bitwise operation来实现。
- 层 + modifier需要单独实现
- 层的 tap 操作需要单独实现
About Rust
变量
rust中变量默认不可变,要可变需要加mut
rust中,还可以用 cosnt
去声明一个常量。声明const的时候,必须指定类型。const一般用大写字母表示。
基础类型
数字
对于数字和基础的变量,rust支持多种进制的表示。还可以添加_
作为虚拟分隔符(主要是为了可读性)。
Number literals | Example |
---|---|
Decimal | 98_222 |
Hex | 0xff |
Octal | 0o77 |
Binary | 0b1111_0000 |
Byte (u8 only) |
b'A' |
浮点数、bool
f32 & f64 & bool,这些通用的,基本都差不多
Tuple
Rust里面也有tuple,用 () 括起来
|
|
还能解组
|
|
Tuple取值,使用 .
:let x = tup.0
array
Array 是一个序列,和tuple的区别是,Array中的数据类型必须一致。
Array还有一个特点:它被分配在stack上,其长度是固定的
|
|
Array的取值,和tuple也不同:let x = a[0]
直接取的话,数组越界会直接panic,需要注意