いろいろなサイトを参考にしながらカスタマイズをした。 実現したい機能ベースで参考をにしたページをまとめる。
参考:
ゼロからキーマップを作るのは現実的でないので、まずは既存のものをコピーしてそれを編集するとしよう。 各キーボードの「Keymaps」フォルダーがあり、 その中にカスタムファームウェアをビルドするためのファイルが格納されている。 まずはここから叩き台となるキーマップをコピーするのだ。
Keymapsフォルダーの中には標準キーマップを示す「defalut」フォルダーのほかに、 ユーザーが作ったキーマップのフォルダーが収録される。 今回は無難なdefaultをコピーしたが、他のユーザーが作ったキーマップをお手本にするのもいいだろう。
実際この通りで、 keymap ディレクトリ内に keymap/default を別名でコピーしたら 新しいキーマップとして認識される。
作ったキーマップを avrdude
で make
するには
make vitamins_included/rev1:part1:avrdude
のように
make [keyboard]:[keymap name]:[firmware]
という書式で指定してあげればよい。上記の例の場合、
default を part1 という名前でコピーしたものを make
している。
layouts ディレクトリのレイアウトを利用することもできる。 自分のキーボードの配列と共通したレイアウトのディレクトリから選択しなければならないが、 後は上記と同じ方法でコンパイル & 書き込みができる。
Have tried
make ergodox:swedish-lindhe
as well asmake keyboard=ergodox keymap=community/swedish-lindhe
but neither works.
keyboards/*/keymaps ではなく、 layouts に作ったものを利用することもできる。 実際に keymaps ディレクトリに作成したキーマップを layouts ディレクトリに移動し、利用してみた。
Supporting a Layout
For a keyboard to support a layout, the variable must be defined in it’s
<keyboard>.h
, and match the number of arguments/keys (and preferably the physical layout):#define LAYOUT_60_ansi KEYMAP_ANSI
The name of the layout must match this regex:
[a-z0-9_]+
The folder name must be added to the keyboard’s
rules.mk
:LAYOUTS = 60_ansi
LAYOUTS
can be set in any keyboard folder level’srules.mk
:LAYOUTS = 60_iso
but the
LAYOUT_<layout>
variable must be defined in<folder>.h
as well.
まず該当する layouts ディレクトリへ移動させる。移動させるディレクトリは keyboards/*/rules.mk 内の
LAYOUTS
に代入されている値が手がかりとなる。
vitamins_included の場合
LAYOUTS = ortho_4x12
なので layouts/community/ortho_4x12 内にディレクトリを移動させればよい。
$ mv part1 ../../../layouts/community/ortho_4x12/leico_part1
$ mv part2 ../../../layouts/community/ortho_4x12/leico_part2
これだけで make
が通ればよかったのだが
$ make vitamins_included/rev1:leico_part2:avrdude
QMK Firmware 0.6.98
Making vitamins_included/rev1 with keymap leico_part2 and target avrdude
avr-gcc (GCC) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Compiling: keyboards/vitamins_included/matrix.c In file included from <command-line>:
./layouts/community/ortho_4x12/leico_part2/config.h:24:10: fatal error: ../../config.h: No such file or directory
#include "../../config.h"
^~~~~~~~~~~~~~~~
compilation terminated.
[ERRORS]
|
|
|
make[1]: *** [.build/obj_vitamins_included_rev1_leico_part2/matrix.o] Error 1
make: *** [vitamins_included/rev1:leico_part2:avrdude] Error 1
Make finished with errors
../../config.h
のインクルードでエラーが発生した。 元のディレクトリ位置から ../../config.h
を探索し、
必要そうな設定をコピーして再度 make
することで書き込みに成功した。
config.h
の中身はこのようになった。
#ifndef CONFIG_USER_H
#define CONFIG_USER_H
#include "config_common.h"
#if !defined(NO_DEBUG) && !defined(CONSOLE_ENABLE)
#define NO_DEBUG
#endif // !NO_DEBUG
#if !defined(NO_PRINT) && !defined(CONSOLE_ENABLE)
#define NO_PRINT
#endif // !NO_PRINT
#define NO_ACTION_MACRO
#define NO_ACTION_FUNCTION
#define DISABLE_LEADER
// hold & tapping delay setting
#define TAPPING_TERM 100
/* Use I2C or Serial, not both */
#define USE_SERIAL
// #define USE_I2C
/* Select hand configuration */
//#define MASTER_LEFT
// #define MASTER_RIGHT
#define EE_HANDS
#ifdef AUDIO_ENABLE
#define DEFAULT_LAYER_SONGS { SONG(QWERTY_SOUND), \
SONG(DVORAK_SOUND), \
SONG(COLEMAK_SOUND) \
}
#endif
#endif
レイヤーのスイッチを行うキー場合、よく見られるのが独自のキーコードを定義している方法。
Defining a New Keycode
The first step to creating your own custom keycode(s) is to enumerate them. This means both naming them and assigning a unique number to that keycode. Rather than limit custom keycodes to a fixed range of numbers QMK provides the
SAFE_RANGE
macro. You can useSAFE_RANGE
when enumerating your custom keycodes to guarantee that you get a unique number.Here is an example of enumerating 2 keycodes. After adding this block to your
keymap.c
you will be able to use FOO and BAR inside your keymap.enum my_keycodes { FOO = SAFE_RANGE, BAR };
独自のキーコードを定義するには上記のように、 enum
で好きな名前で定義をする。
他のキーコードと被らないように、最初の値が SAFE_RANGE
で定義されているので、
この値から開始させるのがよいみたい。
切り替えるべきレイヤーを用意する。
Step 1: Declare
Create each layer as an entry in an enum. Replace YOUR_LAYER_1, YOUR_LAYER_2, etc., below, with names of your layers.
in keymap.c:
// Layer Declarations enum { YOUR_LAYER_1 = 0, YOUR_LAYER_2, // ..., the rest of your layers };
Step 2: Define
Add the keycodes for each layer into the keymaps array, by calling KEYMAP() for each layer.
in keymap.c, create your KEYMAPs:
// Layer Definitions const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { [YOUR_LAYER_1] = KEYMAP( // ... list all your keycodes here, separating each with comma ), [YOUR_LAYER_2] = KEYMAP( // ... list all your keycodes here, separating each with comma ), // ..., the rest of your layers };
このように enum
でレイヤーの重なり順を定義、そしてそれぞれのレイヤーのキーマップを keymaps
配列に定義する。
ただ、キーマップを定義するマクロが変更になっている可能性がある。 Let’s Split - Vitamins included では
LAYOUT_ortho_4x12(
// .....
)
というマクロに変更されていた。
default を参考にすればよい。各種キーの値が既に定義されているのでそれを順番に配置してゆく。
/* Qwerty
* ,-----------------------------------------------------------------------------------.
* | Esc | Q | W | E | R | T | Y | U | I | O | P | Bksp |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | Tab | A | S | D | F | G | H | J | K | L | ; | ' |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | Shift| Z | X | C | V | B | N | M | , | . | / |Enter |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | Ctrl | GUI | Alt |Adjust|Lower |Space |Space |Raise | Left | Down | Up |Right |
* `-----------------------------------------------------------------------------------'
*/
[_QWERTY] = LAYOUT_ortho_4x12( \
KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC, \
KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, \
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT , \
KC_LCTRL,KC_LGUI, KC_LALT, ADJUST, LOWER, KC_SPC, KC_SPC, RAISE, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT \
)
コメントにこのようにキー配列が書かれているのは親切でわかりやすい。
各種キーコードは以下のページにまとめられている。
ページ後方のほうで少しだけ特殊なキーコードに触れる。
#
といった、通常 Shift を押しながら入力するキーを割り当てるキーコードも定義されている。
Keycodes
Key Aliases Description KC_TILDE
KC_TILD
~
KC_EXCLAIM
KC_EXLM
!
KC_AT
@
KC_HASH
#
KC_DOLLAR
KC_DLR
$
KC_PERCENT
KC_PERC
%
KC_CIRCUMFLEX
KC_CIRC
^
KC_AMPERSAND
KC_AMPR
&
KC_ASTERISK
KC_ASTR
*
KC_LEFT_PAREN
KC_LPRN
(
KC_RIGHT_PAREN
KC_RPRN
)
KC_UNDERSCORE
KC_UNDS
_
KC_PLUS
+
KC_LEFT_CURLY_BRACE
KC_LCBR
{
KC_RIGHT_CURLY_BRACE
KC_RCBR
}
KC_PIPE
|
KC_COLON
KC_COLN
:
KC_DOUBLE_QUOTE
KC_DQUO
,KC_DQT
"
KC_LEFT_ANGLE_BRACKET
KC_LABK
,KC_LT
<
KC_RIGHT_ANGLE_BRACKET
KC_RABK
,KC_GT
>
KC_QUESTION
KC_QUES
?
Modifier-Tap shortcuts
長押しで Modifier キー、タップで通常キーを実現する
MT(mod, kc)
の簡易記述です。
Keycode Desc CTL_T(kc)
長押しで Ctrl 、タップで kc SFT_T(kc)
長押しで Shift 、タップで kc ALT_T(kc)
長押しで Alt 、タップで kc GUI_T(kc)
長押しで Gui 、タップで kc ALL_T(kc)
長押しで Ctrl + Shift + Alt + Gui 、タップで kc MEH_T(kc)
長押しで Ctrl + Shift + Alt 、タップで kc LCAG_T(kc)
長押しで Ctrl + Alt + Gui 、タップで kc Samples for Modifier-Tap
CTL_T(KC_Z)
- 長押しで
Ctrl
、タップでZ
。ALL_T(KC_NO)
- 長押しで
Hyper
、タップで何もしない
。ALT_T(KC_APP)
- 長押しで
Alt
、タップでAPP
。
For convenience, QMK includes some Mod-Tap shortcuts to make common combinations more compact in your keymap:
Key Aliases Description LCTL_T(kc)
CTL_T(kc)
Left Control when held, kc
when tappedRCTL_T(kc)
Right Control when held, kc
when tappedLSFT_T(kc)
SFT_T(kc)
Left Shift when held, kc
when tappedRSFT_T(kc)
Right Shift when held, kc
when tappedLALT_T(kc)
ALT_T(kc)
Left Alt when held, kc
when tappedRALT_T(kc)
ALGR_T(kc)
Right Alt when held, kc
when tappedLGUI_T(kc)
LCMD_T(kc)
,RWIN_T(kc)
,GUI_T(kc)
Left GUI when held, kc
when tappedRGUI_T(kc)
RCMD_T(kc)
,RWIN_T(kc)
Right GUI when held, kc
when tappedC_S_T(kc)
Left Control and Shift when held, kc
when tappedMEH_T(kc)
Left Control, Shift and Alt when held, kc
when tappedLCAG_T(kc)
Left Control, Alt and GUI when held, kc
when tappedRCAG_T(kc)
Right Control, Alt and GUI when held, kc
when tappedALL_T(kc)
Left Control, Shift, Alt and GUI when held, kc
when tapped - more info hereSGUI_T(kc)
SCMD_T(kc)
,SWIN_T(kc)
Left Shift and GUI when held, kc
when tappedLCA_T(kc)
Left Control and Alt when held, kc
when tapped
長押しで Shift 、タップで Space を実現するには LSFT_T(KC_SPC)
を割り当てたいキーの位置に記述する。
[ ANY_LAYER ] = LAYOUT_ortho_4x12( ....., LSFT_T(KC_SPC), .....
)
上記設定を行った後、スペースの入力が少しもっさりしている気がした。
Stick this in your config.h and modify it.
#define TAPPING_TERM 200
TAPPING_TERM
で入力までのディレイ、ひいては長押しとタップ判定時間を変更できるようだ。
config.h に TAPPING_TERM 100
を設定することで解決した。
一番簡単にレイヤーを切り替える方法はキーコードで既に実装されている。
Layer
https://github.com/jackhumbert/qmk_firmware#switching-and-toggling-layers
Keycode Mean Desc TO(layer, when)
GOTO layer レイヤー移動(whenは1(ON_PRESS)推奨) MO(layer)
Momentary 押している間だけ指定したレイヤー OSL(layer)
One-shot layer 次の1キーだけ指定したレイヤー LT(layer, kc)
Layer / Tap 押している間だけ指定したレイヤー、タップでkc TG(layer)
Toggle layer タップして指定したレイヤー、再タップで戻る(※) DF(layer)
Default layer デフォルトレイヤーの変更(電源OFFまで継続) ※ 行き先のレイヤーには同じキーに
KC_TRNS
を割り当てる必要あり
Step 3: Use
Here are a variety of ways to change the layer.
Keycode to be added to your call to KEYMAP() Description MO(YOUR_LAYER) While held, MOmentarily switch to YOUR_LAYER. LT(YOUR_LAYER, KC_XXXX) Layer Tap. When held: go to YOUR_LAYER. When tapped: send KC_XXXX TG(YOUR_LAYER) Layer Toggle. When tapped, toggles YOUR_LAYER on or off TO(YOUR_LAYER) When tapped, goes to YOUR_LAYER TT(YOUR_LAYER) When tapped, toggles YOUR_LAYER on or off.When held, activates YOUR_LAYER. OSL(YOUR_LAYER) One-Shot Layer. Goes to YOUR_LAYER for the next keypress
以下のようにレイヤーを定義した場合、
enum layers {
LAYER1 = 0
, LAYER2
};
レイヤー1 から レイヤー2 へ、押しっぱなしの時だけ変更するボタンを作るには
[LAYER1] = LAYOUT_ortho_4x12( ....., MO( LAYER2 ), .....
)
という記述をすると実現できる。 ただ切り替えたいだけの場合はこれが有効。
Respective layers can be validated simultaneously. Layers are indexed with 0 to 31 and higher layer has precedence.
Keymap: 32 Layers Layer: action code matrix ----------------- --------------------- stack of layers array_of_action_code[row][column] ____________ precedence _______________________ / / | high / ESC / F1 / F2 / F3 .... 31 /___________// | /-----/-----/-----/----- 30 /___________// | / TAB / Q / W / E .... 29 /___________/ | /-----/-----/-----/----- : _:_:_:_:_:__ | : /LCtrl/ A / S / D .... : / : : : : : / | : / : : : : 2 /___________// | 2 `-------------------------- 1 /___________// | 1 `-------------------------- 0 /___________/ V low 0 `--------------------------
Sometimes, the action code stored in keymap may be referred as keycode in some documents due to the TMK history.
数字の小さい方から順番に上にレイヤーがオーバーラップしてゆく仕組みになっている。
Layer Precedence and Transparency
Note that higher layer has higher priority on stack of layers, namely firmware falls down from top layer to bottom to look up keycode. Once it spots keycode other than
KC_TRNS
(transparent) on a layer it stops searching and lower layers aren’t referred.You can place
KC_TRANS
on overlay layer changes just part of layout to fall back on lower or base layer. Key withKC_TRANS
(KC_TRNS
and_______
are the alias) doesn’t has its own keycode and refers to lower valid layers for keycode, instead.
KC_TRANS
が設定されたキーはキーコードを持たず、下位レイヤーのキーコードがそのまま利用される。
キーコードが見つかるまで下位レイヤーが探索される。
Programming the Behavior of Any Keycode
When you want to override the behavior of an existing key, or define the behavior for a new key, you should use the
process_record_kb()
andprocess_record_user()
functions. These are called by QMK during key processing before the actual key event is handled. If these functions returntrue
QMK will process the keycodes as usual. That can be handy for extending the functionality of a key rather than replacing it. If these functions returnfalse
QMK will skip the normal key handling, and it will be up to you to send any key up or down events that are required.These function are called every time a key is pressed or released. Example
process_record_user()
ImplementationThis example does two things. It defines the behavior for a custom keycode called
FOO
, and it supplements our Enter key by playing a tone whenever it is pressed.bool process_record_user(uint16_t keycode, keyrecord_t *record) { switch (keycode) { case FOO: if (record->event.pressed) { // Do something when pressed } else { // Do something else when release } return false; // Skip all further processing of this key case KC_ENTER: // Play a tone when enter is pressed if (record->event.pressed) { PLAY_NOTE_ARRAY(tone_qwerty); } return true; // Let QMK send the enter press/release events default: return true; // Process all other keycodes normally } }
独自で定義したキーコードは、
bool process_record_user(uint16_t keycode, keyrecord_t *record)
関数でイベントを取得できる。この関数はキーが押された、または離された時に呼び出される。
キーの状態は record -> event.pressed
で取得できる。このパラメータは
/* Key event container for recording */ typedef struct { keyevent_t event; #ifndef NO_ACTION_TAPPING tap_t tap; #endif } keyrecord_t;
/* key event */ typedef struct { keypos_t key; bool pressed; uint16_t time; } keyevent_t;
と定義されていたので、キーが押されると true
、離れると false
となるようだ。
この関数自体が true
を返すと続けて既存のキーコード処理が行われる(存在する場合)。
false
を返すと既存の処理は行われずに完全な処理の上書きとなる。
自ら定義したキーの挙動は、 keycode で条件分岐を行ってそれぞれ実装してゆく。
case LOWER: if (record->event.pressed) { layer_on(_LOWER); update_tri_layer(_LOWER, _RAISE, _ADJUST); } else { layer_off(_LOWER); update_tri_layer(_LOWER, _RAISE, _ADJUST); } return false; break;
vitamins included のキーマップのソースはこのようにしてレイヤーの切り替えを行っていた。
layer_on
、 layer_off
以外にもレイヤー関係の関数がありそうだ。
Sometimes, you might want to switch between layers in a macro or as part of a tap dance routine.
layer_on
activates a layer, andlayer_off
deactivates it. More layer-related functions can be found in action_layer.h.
レイヤーに関する関数は action_layer.h
に書かれているらしい。
使いそうなものをちょっとだけまとめてみる。
extern uint32_t layer_state;
void layer_clear(void) { layer_state_set(0); } /** \brief Layer state is * * FIXME: Needs docs */ bool layer_state_is(uint8_t layer) { return layer_state_cmp(layer_state, layer); } /** \brief Layer state compare * * FIXME: Needs docs */ bool layer_state_cmp(uint32_t cmp_layer_state, uint8_t layer) { if (!cmp_layer_state) { return layer == 0; } return (cmp_layer_state & (1UL<<layer)) != 0; } ... /** \brief Layer on * * FIXME: Needs docs */ void layer_on(uint8_t layer) { layer_state_set(layer_state | (1UL<<layer)); } /** \brief Layer off * * FIXME: Needs docs */ void layer_off(uint8_t layer) { layer_state_set(layer_state & ~(1UL<<layer)); }
layer_state
layer_state
に保存される。何かレイヤーが有効になると、layer_state
の該当するレイヤーのビットが 1 になる。
layer_state
は uint32_t
型なので最大 32 のレイヤーを保持することができる。という仕組みである。layer_on
layer_state
の現在値との OR 演算を行う。
結果として対象のレイヤーを有効化する。layer_off
layer_state
の現在値との AND 演算を行う。
結果として対象のレイヤーを無効化する。layer_clear
layer_state_cmp
true
、無効の場合 false
を返す。
layer_state_is
の準備関数っぽい。layer_state_is
true
、 false
で返す。この辺りのものを組み合わせると複雑な切り替えが実現できそうだ。
The first is the
update_tri_layer(x, y, z)
function.
This function check to see if layersx
andy
are both on. If they are both on, then it runs on layerz
.
Otherwise, if bothx
andy
are not both on (either only one is, or neither is), then it runs off layerz
.
レイヤーボタンの組み合わせだけでどうにかなる場合はこの関数を利用すると簡単。 書いてあるとおり、2つのレイヤーの状態をチェックし、両方とも有効の場合、3つ目のレイヤーを有効化する。
3つ目のレイヤーが最上位、つまり一番大きな数字が割り当てられているのが定石だが、 前2つより小さな数字を割り当て、透過しているキーの挙動を変更する、という使い方もできる。
左右にそれぞれレイヤー切り替えボタンがある時のレイヤー切り替えを考える。 普通に on/off するだけでは両方を押さえていた場合、片方を離してしまうだけでレイヤーが off になってしまう。
左右のキーの状態を保持しておく方法で解決した。
void DualKeyPressed ( bool brother_state, uint8_t target ){
if( brother_state ) return;
layer_on( target );
return;
}
void DualKeyReleased ( bool brother_state, uint8_t target1 ){
if( brother_state ) return ;
layer_off( target1 );
return ;
}
bool LayerSwitch ( keyrecord_t *record, bool *key_state, bool brother, uint8_t layer ){
if ( record -> event.pressed ) {
*key_state = true;
DualKeyPressed( brother, layer );
}
else {
*key_state = false;
DualKeyReleased( brother, layer );
}
update_tri_layer(_LOWER, _RAISE, _NEUTRAL );
return false;
}
...
static bool l_lower = false;
static bool r_lower = false;
switch (keycode) {
//left lower setting
case L_LOWER :
return LayerSwitch( record, &l_lower, r_lower, _LOWER );
break;
//right lower setting
case R_LOWER :
return LayerSwitch( record, &r_lower, l_lower, _LOWER );
break;
...
キー入力がなされた時点で自身の状態を記録、その後もう一方のキーの状態を調べ、押されていない場合は有効化、または無効化を行う。
レイヤーを切り替えるボタンが押された上で、別のキーが入力されるとレイヤーが一段深くなるような挙動を実現するコードを、 このように実装した。
void ComboPressed( bool brother_state ){
if( brother_state ) return;
if( layer_state_is( _LOWER ) ){
layer_on( _LOWER_COMBO );
return;
}
if( layer_state_is( _RAISE ) ){
layer_on( _RAISE_COMBO );
return ;
}
}
void ComboReleased ( bool brother_state ){
if( brother_state ) return;
if( layer_state_is( _LOWER_COMBO ) ){
layer_off( _LOWER_COMBO );
return;
}
if( layer_state_is( _RAISE_COMBO ) ) {
layer_off( _RAISE_COMBO );
return;
}
}
void DualKeyPressed ( bool brother_state, uint8_t target ){
if( brother_state ) return;
layer_on( target );
return;
}
bool DualKeyReleased ( bool brother_state, uint8_t target1, uint8_t target2 ){
if( brother_state ) return false;
layer_off( target1 );
layer_off( target2 );
return true;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
static bool l_lower = false;
static bool r_lower = false;
static bool l_raise = false;
static bool r_raise = false;
static bool l_combo = false;
static bool r_combo = false;
switch (keycode) {
//left lower setting
case L_LOWER :
if ( record -> event.pressed ) {
l_lower = true;
DualKeyPressed( r_lower, _LOWER );
}
else {
l_lower = false;
if ( DualKeyReleased( r_lower, _LOWER, _LOWER_COMBO ) ){
l_combo = false;
r_combo = false;
}
}
return false;
break;
//right lower setting
case R_LOWER :
if ( record -> event.pressed ) {
r_lower = true;
DualKeyPressed( l_lower, _LOWER );
}
else {
r_lower = false;
if( DualKeyReleased( l_lower, _LOWER, _LOWER_COMBO ) ){
l_combo = false;
r_combo = false;
}
}
return false;
break;
//left raise setting
case L_RAISE :
if ( record -> event.pressed ) {
l_raise = true;
DualKeyPressed( r_raise, _RAISE );
}
else {
l_raise = false;
if ( DualKeyReleased( r_raise, _RAISE, _RAISE_COMBO ) ){
l_combo = false;
r_combo = false;
}
}
return false;
break;
//right raise setting
case R_RAISE :
if ( record -> event.pressed ) {
r_raise = true;
DualKeyPressed( l_raise, _RAISE );
}
else {
r_raise = false;
if ( DualKeyReleased( l_raise, _RAISE, _RAISE_COMBO ) ){
l_combo = false;
r_combo = false;
}
}
return false;
break;
//left combo setting
case L_COMBO :
if( record -> event.pressed ){
l_combo = true;
ComboPressed( r_combo );
}
else{
l_combo = false;
ComboReleased( r_combo );
}
return false;
break;
//right combo setting
case R_COMBO :
if( record -> event.pressed ) {
r_combo = true;
ComboPressed( l_combo );
}
else{
r_combo = false;
ComboReleased( l_combo );
}
return false ;
break;
}
return true;
}
全て組となったキーになっている。 Lower と Raise はキーマップの方で同時には押せないようにしている。 一段深い Lower Combo と Raise Combo レイヤーへの移行は同じ Combo と名付けたキーを利用する。
以下に記載したmodifierキーがロックされる事象は、 QMKのreadmeのPrevent stuck modifiers に記載されていることを みやおかさんから教えていただき、 その通りであることを確認しました。
Prevent stuck modifiers
Consider the following scenario:
- Layer 0 has a key defined as Shift.
- The same key is defined on layer 1 as the letter A.
- User presses Shift.
- User switches to layer 1 for whatever reason.
- User releases Shift, or rather the letter A.
- User switches back to layer 0.
Shift was actually never released and is still considered pressed.
If such situation bothers you add this to your
config.h
:#define PREVENT_STUCK_MODIFIERS
This option uses 5 bytes of memory per every 8 keys on the keyboard rounded up (5 bits per key). For example on Planck (48 keys) it uses (48/8)*5 = 30 bytes.
/* Raise
* ,------------------------------------------------------------------------------------.
* | Esc | | & | { | } | % || \ | [ | ] | # | | Bksp |
* |------+------+------+------+------+------++------+------+------+------+------+------|
* | Ctrl | ~ | | | ( | ) | * || / | < | > | ' | : |Enter |
* |------+------+------+------+------+------++------+------+------+------+------+------|
* | Tab | ` | ^ | @ | $ | + || - | = | _ | " | ? | GUI |
* |------+------+------+------+------+------++------+------+------+------+------+------|
* | | | | | |LSFT_T||RSFT_T| | | | | |
* |Reset | Alt | GUI |LLower|LRaise|Space ||Space |RRaise|RLower| | Del |Reset |
* `------------------------------------------------------------------------------------'
*/
[_RAISE] = LAYOUT_ortho_4x12( \
_______, XXXXXXX, KC_AMPR, KC_LCBR, KC_RCBR, KC_PERC, KC_BSLS, KC_LBRC, KC_RBRC, KC_HASH, XXXXXXX, _______, \
_______, KC_TILD, KC_PIPE, KC_LPRN, KC_RPRN, KC_ASTR, KC_SLSH, KC_LABK, KC_RABK, KC_QUOT, KC_COLN, _______, \
_______, KC_GRV, KC_CIRC, KC_AT, KC_DLR, KC_PLUS, KC_MINS, KC_EQL, KC_UNDS, KC_DQUO, KC_QUES, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
),
このキーマップの下部を
_______, _______, _______, _______, _______, KC_A, _______, _______, _______, _______, _______, _______ \
_______, _______, _______, _______, _______, _______, _______, KC_A, _______, _______, _______, _______ \
として実験した。
ちゃんと機能していることがわかった。 容量に余裕があるのであればこの設定は入れたままのほうが良い気がする。