zmk に統一できた、キーボードは二種類。Kinesis と ferris/sweep を設定します。

Kinesis Advantage 360

大枚はたいて kinesis 社の Advantage360 Pro というキーボードを買った。 どうせここまで来たなら、もうやけになって、新しいキーボードレイアウトも習得してしまおうと思う。(colemak DHにした。)

いろいろ変更する手順はあるんだけど、キーボード側でキーの挙動を定義する事が出来るので、ここでその手順を記録しておく。

web でマッピングを変更する

https://kinesiscorporation.github.io/Adv360-Pro-GUI に web アプリがあって、そこでかえたものを

https://github.com/yasushisakai/Adv360-Pro-ZMK/actions へ反映する権限をあたえれば、変更して自動でコミットしてくれる。

Kinesis Advantage 360 Pro は、zmk が基本になっていて、そのルールに従って変更すればいい。

ファームウェアの更新

web 経由で変更するなり、手打でかえるなり、コミットされると、actions が働いて、新しいファームウェアをコンパイルしてくれる。それをダウンロードする。

コンピュータとキーボードを接続して、リセットボタンをおすと、マウントされので、左右対応する方のファームウェアをドラッグドロップ。

ferris/sweep

https://zmk.dev/docs/user-setup

  • github で新しいレポジトリを作る。
  • 下記実行
bash -c "$(curl -fsSL https://zmk.dev/setup.sh)"

とりあえず、Keyboard Selection は 20) Cradio/Sweepc で、MCU は 9) nice!nano v2 を選択。

Keymap.config

レイアウト図

手で(マニュアル?)かえる場合は基本的に下記の規則で記述していく。

kinesis 自体はこうゆう配列であって、

kinesis_array_num.png

もし Kinesis に慣れてしまった場合に、 qwerty が億劫になるはずで、そこまで Colemak になれたら 携帯用のキーボードをつくるんだと思う。その時はいちおう 36key にしようと決めているので、そうなっても困らないマッピングにしておく。というか、34 key ありきの Mapping にする。これは、上の配列の情報を以下の用に再マッピングすればいい事になる。

kinesis_36_area.png

Figure 1: 紫の●はリセットボタン

参考として、Miryoku というレイアウトがあるらしいが、マウスやメディア操作はいらないかなと。それ以外だったら、ベンの 34key layout があるけど、日本語を打つ事を考えると多少考えないといけない。(36 がいいと思ったのもこの理由から。)

色々検討した結果、下記を目標にしようと思う。

kinesis_layout.png

変更履歴

<2023-01-27 Fri>

  • esc がレイヤー 2 にしかなかったのが、つらいので、いくつかためしてみてる。
  • sticky shift あんまりつかってないから、そこも esc にしてみた。
  • グラフィックソフトを使う時にどうしても space と enter が、左手にあったほうが良いから、試す。

<2023-01-28 Sat>

  • 34 key に挑戦

<2023-04-01 Sat>

  • 元 repo いつのまにかキーが増えていた。
  • vim の操作感が恋しくて、qwerty になおす。

<2023-08-29 Tue> (未適応)

  • BTC (bluetooth の設定をクリア)をなくす、ふとした反動で押しやすいので
  • qmk と音の制御キーを統一

<2023-11-29 Wed>

  • BTC (bluetooth の設定をクリア)復活
  • qmk と音の制御キーを統一

<2024-01-18 Thu>

  • bluetooth の切り替え機能をやめる
  • function layer は Numbers & Arrows の最中でかつ親指を押している間だけにした。

ヘッダ諸々

  • Kinesis
    /* THIS FILE WAS GENERATED!
     *
     * This file was generated automatically. You may or may not want to
     * edit it directly.https://yasushisakai.com/kinesis_Advantage_360_Pro.html
     */
    
    #include <behaviors.dtsi>
    #include <dt-bindings/zmk/keys.h>
    #include <dt-bindings/zmk/bt.h>
    #include <dt-bindings/zmk/rgb.h>
    #include <dt-bindings/zmk/backlight.h>
    
    / {
    
  • sweep / ferris
    /* THIS FILE WAS GENERATED!
     *
     * This file was generated automatically. You may or may not want to
     * edit it directly.https://yasushisakai.com/kinesis_Advantage_360_Pro.html
     */
    
    #include <behaviors.dtsi>
    #include <dt-bindings/zmk/keys.h>
    #include <dt-bindings/zmk/bt.h>
    
    / {
    
    

ビヘイビア(挙動)の定義

ホーム行の長押しもしくは、別のキーとの同時押しの場合の挙動は、 &hm とする。これをキーボード界隈だと、home row mods というらしい。ただの長押しじゃあダメらしく、この挙動についての詳しい説明はここで読めます。なかなか奥が深い。

普通は &kp 普通の長押しは &hd

あとは、 &none, &trans, &sk とかある。

  • Kinesis
      behaviors {
        #include "macros.dtsi"
    
        hm: homerow_mods {
            compatible = "zmk,behavior-hold-tap";
            label = "HOMEROW_MODS";
            #binding-cells = <2>;
            tapping-term-ms = <200>;
            quick_tap_ms = <175>;
            flavor = "tap-preferred";
            bindings = <&kp>, <&kp>;
        };
    
        hml: homerow_layer_reset {
            compatible = "zmk,behavior-hold-tap";
            label = "HOMEROW_MODS_LAYER_RESET";
            #binding-cells = <2>;
            tapping-term-ms = <200>;
            quick_tap_ms = <175>;
            flavor = "tap-preferred";
            bindings = <&kp>, <&to>;
        };
    
        hd: hold {
                compatible = "zmk,behavior-hold-tap";
                label = "HOLD";
                #binding-cells = <2>;
                tapping-term-ms = <150>;
                quick_tap_ms = <0>;
                flavor = "tap-preferred";
                bindings = <&kp>, <&kp>;
        };
        td_mt: tap_dance_mod_tap {
                compatible = "zmk,behavior-tap-dance";
                label = "TAP_DANCE_MOD_TAP";
                #binding-cells = <0>;
                tapping-term-ms = <200>;
                bindings = <&mt LC(LS(LALT)) ESC>, <&to 1>;
        };
      };
    
  • sweep / ferris
      behaviors {
        #include "macros.dtsi"
    
        hm: homerow_mods {
            compatible = "zmk,behavior-hold-tap";
            label = "HOMEROW_MODS";
            #binding-cells = <2>;
            tapping-term-ms = <200>;
            quick_tap_ms = <175>;
            flavor = "tap-preferred";
            bindings = <&kp>, <&kp>;
        };
    
        hml: homerow_layer_reset {
            compatible = "zmk,behavior-hold-tap";
            label = "HOMEROW_MODS_LAYER_RESET";
            #binding-cells = <2>;
            tapping-term-ms = <200>;
            quick_tap_ms = <175>;
            flavor = "tap-preferred";
            bindings = <&kp>, <&to>;
        };
    
        hd: hold {
                compatible = "zmk,behavior-hold-tap";
                label = "HOLD";
                #binding-cells = <2>;
                tapping-term-ms = <150>;
                quick_tap_ms = <0>;
                flavor = "tap-preferred";
                bindings = <&kp>, <&kp>;
        };
        td_mt: tap_dance_mod_tap {
                compatible = "zmk,behavior-tap-dance";
                label = "TAP_DANCE_MOD_TAP";
                #binding-cells = <0>;
                tapping-term-ms = <200>;
                bindings = <&mt LC(LS(LALT)) ESC>, <&to 1>;
        };
      };
    

マッピングをメタプログラミング

https://zmk.dev/docs/codes

Kinesis と sweep 両方一気に設定します。

def mapkey(keys, layout, mapping):
    for i in range(len(keys)):
        layout[mapping[i]] = keys[i]

    return layout

def maplayer(num_keys, top, middle, bottom, thumb, default, top_mapping, middle_mapping, bottom_mapping, thumb_mapping):
    layer = [default] * num_keys
    layer = mapkey(top,layer,top_mapping)
    layer = mapkey(middle,layer,middle_mapping)
    layer = mapkey(bottom,layer,bottom_mapping)
    layer = mapkey(thumb,layer,thumb_mapping)
    return layer

def makelayer(layer_name, num_keys, top, middle, bottom, thumb, default, top_mapping, middle_mapping, bottom_mapping, thumb_mapping):
    keys = maplayer(num_keys, top, middle, bottom, thumb, default, top_mapping, middle_mapping, bottom_mapping, thumb_mapping);
    mappings = '  '.join(keys)
    return f'{layer_name} {{\n    bindings = <\n{mappings}\n    >;\n  }};'

def makemap(path, num_keys, top_mapping, middle_mapping, bottom_mapping, thumb_mapping, is_kinesis=False):

    ## default layer
    top = ['&hd ESC Q'] + [f'&kp {i}' for i in 'WE'] + ['&hd LPAR R', '&hd RPAR T', '&kp Y', '&kp U', '&hd LBKT I', '&hd RBKT O', '&hd MINUS P']
    middle = ['&kp A', '&hm LCTRL S', '&hm LALT D', '&hm LSHIFT F', '&hm LGUI G', '&hm RGUI H', '&hm RSHIFT J', '&hm LALT K', '&hm RCTRL L', '&hd EQUAL SEMI']
    bottom = ['&hd TAB Z'] + [f'&kp {i}' for i in 'XCVBNM'] + ['&kp COMMA', '&kp DOT', '&hd SQT FSLH']
    thumb = ['&kp SPACE', '&kp ENTER', '&hml LC(LS(LALT)) 1', '&kp BSPC' ]
    default_layer = makelayer('default_layer', num_keys, top, middle, bottom, thumb, '&none', top_mapping, middle_mapping, bottom_mapping, thumb_mapping)

    ### numbers and arrows
    top = ['&kp ESC'] + [f'&kp N{i}' for i in '7890'] + ['&trans']*2 + ['&kp LBKT', '&kp RBKT', '&kp BSLH']
    middle = ['&kp TAB', '&hm LCTRL N4', '&hm LALT N5', '&hm LSHIFT N6', '&hm LGUI MINUS', '&hm RGUI LEFT', '&hm RSHIFT DOWN', '&hm LALT UP', '&hm RCTRL RIGHT', '&kp SQT']
    bottom = ['&kp GRAVE'] + [f'&kp N{i}' for i in '123'] + ['&kp EQUAL']
    thumb = ['&trans'] * 4 # this wil be used in the layer below as well
    thumb[0] = '&to 0'
    thumb[2] = '&mo 2'
    number_layer = makelayer('number_layer', num_keys, top, middle, bottom, thumb, '&trans', top_mapping, middle_mapping, bottom_mapping, thumb_mapping)

    ### functions

    # kinesis has a backlight
    right_lower_2 = '&trans';
    right_lower_3 = '&trans';

    if (is_kinesis) :
        right_lower_2 = '&bl BL_OFF'
        right_lower_3 = '&bl BL_ON'

    top = ['&trans'] + [f'&kp F{i}' for i in range(7,11)] + ['&trans'] * 4 + ['&kp C_VOL_UP']
    middle = ['&trans'] + [f'&kp F{i}' for i in range(4,7)] + ['&kp F11' ] + ['&trans'] * 4 + ['&kp C_MUTE']
    bottom = ['&trans'] + [f'&kp F{i}' for i in range(1,4)] + ['&kp F12', '&trans', right_lower_2, right_lower_3, '&trans', '&kp C_VOL_DN']
    thumb[1] = '&bt BT_CLR'
    function_layer = makelayer('function_layer', num_keys, top, middle, bottom, thumb, '&trans', top_mapping, middle_mapping, bottom_mapping, thumb_mapping)

    ### put it all together
    layers = f'#+begin_src text :tangle {path}\n'
    layers += f'keymap {{\n\n  compatible = "zmk,keymap"; \n\n  {default_layer} \n\n  {number_layer} \n\n  {function_layer}\n}};'
    layers += '};\n' # the last bracket to close the root object
    layers += '#+end_src'
    return layers

out = '';

### Kinesis
layer_key_num = [14,14,20,20,16]
num_keys = sum(layer_key_num)
top_mapping = [i + sum(layer_key_num[0:1]) for i in [1,2,3,4,5,8,9,10,11,12]]
middle_mapping = [i + sum(layer_key_num[0:2]) for i in [1,2,3,4,5,14,15,16,17,18]]
bottom_mapping = [i + sum(layer_key_num[0:3])  for i in [1,2,3,4,5,14,15,16,17,18]]
thumb_mapping = [i + sum(layer_key_num[0:4]) for i in [5,6,9,10]]

out += makemap('~/code/Adv360-Pro-ZMK/config/adv360.keymap', num_keys, top_mapping, middle_mapping, bottom_mapping, thumb_mapping, True)

out += '\n\n'

### sweep
layer_key_num = [0,10,10,10,4]
num_keys = sum(layer_key_num)
top_mapping = [i + sum(layer_key_num[0:1]) for i in range(10)]
middle_mapping = [i + sum(layer_key_num[0:2]) for i in range(10)]
bottom_mapping = [i + sum(layer_key_num[0:3])  for i in range(10)]
thumb_mapping = [i + sum(layer_key_num[0:4]) for i in range(4)]

out += makemap('~/code/sweep-zmk/config/cradio.keymap', num_keys, top_mapping, middle_mapping, bottom_mapping, thumb_mapping)

return out
keymap {

  compatible = "zmk,keymap";

  default_layer {
    bindings = <
&none  &none  &none  &none  &none  &none  &none  &none  &none  &none  &none  &none  &none  &none  &none  &hd ESC Q  &kp W  &kp E  &hd LPAR R  &hd RPAR T  &none  &none  &kp Y  &kp U  &hd LBKT I  &hd RBKT O  &hd MINUS P  &none  &none  &kp A  &hm LCTRL S  &hm LALT D  &hm LSHIFT F  &hm LGUI G  &none  &none  &none  &none  &none  &none  &none  &none  &hm RGUI H  &hm RSHIFT J  &hm LALT K  &hm RCTRL L  &hd EQUAL SEMI  &none  &none  &hd TAB Z  &kp X  &kp C  &kp V  &kp B  &none  &none  &none  &none  &none  &none  &none  &none  &kp N  &kp M  &kp COMMA  &kp DOT  &hd SQT FSLH  &none  &none  &none  &none  &none  &none  &kp SPACE  &kp ENTER  &none  &none  &hml LC(LS(LALT)) 1  &kp BSPC  &none  &none  &none  &none  &none
    >;
  };

  number_layer {
    bindings = <
&trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &kp ESC  &kp N7  &kp N8  &kp N9  &kp N0  &trans  &trans  &trans  &trans  &kp LBKT  &kp RBKT  &kp BSLH  &trans  &trans  &kp TAB  &hm LCTRL N4  &hm LALT N5  &hm LSHIFT N6  &hm LGUI MINUS  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &hm RGUI LEFT  &hm RSHIFT DOWN  &hm LALT UP  &hm RCTRL RIGHT  &kp SQT  &trans  &trans  &kp GRAVE  &kp N1  &kp N2  &kp N3  &kp EQUAL  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &to 0  &trans  &trans  &trans  &mo 2  &trans  &trans  &trans  &trans  &trans  &trans
    >;
  };

  function_layer {
    bindings = <
&trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &kp F7  &kp F8  &kp F9  &kp F10  &trans  &trans  &trans  &trans  &trans  &trans  &kp C_VOL_UP  &trans  &trans  &trans  &kp F4  &kp F5  &kp F6  &kp F11  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &kp C_MUTE  &trans  &trans  &trans  &kp F1  &kp F2  &kp F3  &kp F12  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &trans  &bl BL_OFF  &bl BL_ON  &trans  &kp C_VOL_DN  &trans  &trans  &trans  &trans  &trans  &trans  &to 0  &bt BT_CLR  &trans  &trans  &mo 2  &trans  &trans  &trans  &trans  &trans  &trans
    >;
  };
};};
keymap {

  compatible = "zmk,keymap";

  default_layer {
    bindings = <
&hd ESC Q  &kp W  &kp E  &hd LPAR R  &hd RPAR T  &kp Y  &kp U  &hd LBKT I  &hd RBKT O  &hd MINUS P  &kp A  &hm LCTRL S  &hm LALT D  &hm LSHIFT F  &hm LGUI G  &hm RGUI H  &hm RSHIFT J  &hm LALT K  &hm RCTRL L  &hd EQUAL SEMI  &hd TAB Z  &kp X  &kp C  &kp V  &kp B  &kp N  &kp M  &kp COMMA  &kp DOT  &hd SQT FSLH  &kp SPACE  &kp ENTER  &hml LC(LS(LALT)) 1  &kp BSPC
    >;
  };

  number_layer {
    bindings = <
&kp ESC  &kp N7  &kp N8  &kp N9  &kp N0  &trans  &trans  &kp LBKT  &kp RBKT  &kp BSLH  &kp TAB  &hm LCTRL N4  &hm LALT N5  &hm LSHIFT N6  &hm LGUI MINUS  &hm RGUI LEFT  &hm RSHIFT DOWN  &hm LALT UP  &hm RCTRL RIGHT  &kp SQT  &kp GRAVE  &kp N1  &kp N2  &kp N3  &kp EQUAL  &trans  &trans  &trans  &trans  &trans  &to 0  &trans  &mo 2  &trans
    >;
  };

  function_layer {
    bindings = <
&trans  &kp F7  &kp F8  &kp F9  &kp F10  &trans  &trans  &trans  &trans  &kp C_VOL_UP  &trans  &kp F4  &kp F5  &kp F6  &kp F11  &trans  &trans  &trans  &trans  &kp C_MUTE  &trans  &kp F1  &kp F2  &kp F3  &kp F12  &trans  &trans  &trans  &trans  &kp C_VOL_DN  &to 0  &bt BT_CLR  &mo 2  &trans
    >;
  };
};};

メタプログラミング

上のやつの簡易版

sweep のやつだったけど、怖いから少しの間残しておく。

### constants
layer_key_num = [0,10,10,10,4]
TOTAL_NUM_KEYS = sum(layer_key_num)
top_mapping = [i + sum(layer_key_num[0:1]) for i in range(10)]
middle_mapping = [i + sum(layer_key_num[0:2]) for i in range(10)]
bottom_mapping = [i + sum(layer_key_num[0:3])  for i in range(10)]
thumb_mapping = [i + sum(layer_key_num[0:4]) for i in range(4)]

def mapkey(keys, layout, mapping):
    for i in range(len(keys)):
        layout[mapping[i]] = keys[i]

    return layout

def maplayer(top, middle, bottom, thumb, default):
    layer = [default] * TOTAL_NUM_KEYS
    layer = mapkey(top,layer,top_mapping)
    layer = mapkey(middle,layer,middle_mapping)
    layer = mapkey(bottom,layer,bottom_mapping)
    layer = mapkey(thumb,layer,thumb_mapping)
    return layer

def makelayer(layer_name, top, middle, bottom, thumb, default='&none'):
    keys = maplayer(top, middle, bottom, thumb, default)
    mappings = '  '.join(keys)
    return f'{layer_name} {{\n    bindings = <\n{mappings}\n    >;\n  }};'

### default layer
top = ['&hd ESC Q'] + [f'&kp {i}' for i in 'WE'] + ['&hd LPAR R', '&hd RPAR T', '&kp Y', '&kp U', '&hd LBKT I', '&hd RBKT O', '&hd MINUS P']
middle = ['&kp A', '&hm LCTRL S', '&hm LALT D', '&hm LSHIFT F', '&hm LGUI G', '&hm RGUI H', '&hm RSHIFT J', '&hm LALT K', '&hm RCTRL L', '&hd EQUAL SEMI']
bottom = ['&hd TAB Z'] + [f'&kp {i}' for i in 'XCVBNM'] + ['&kp COMMA', '&kp DOT', '&hd SQT FSLH']
thumb = ['&kp SPACE', '&kp ENTER', '&hml LC(LS(LALT)) 1', '&kp BSPC' ]
default_layer = makelayer('default_layer', top, middle, bottom, thumb)

### numbers and arrows
top = ['&kp ESC'] + [f'&kp N{i}' for i in '7890'] + ['&trans']*2 + ['&kp LBKT', '&kp RBKT', '&kp BSLH']
middle = ['&kp TAB', '&hm LCTRL N4', '&hm LALT N5', '&hm LSHIFT N6', '&hm LGUI MINUS', '&hm RGUI LEFT', '&hm RSHIFT DOWN', '&hm LALT UP', '&hm RCTRL RIGHT', '&kp SQT']
bottom = ['&kp GRAVE'] + [f'&kp N{i}' for i in '123'] + ['&kp EQUAL']
thumb = ['&trans'] * 4
thumb[0] = '&to 0'
thumb[2] = '&mo 2'
number_layer = makelayer('number_layer', top, middle, bottom, thumb, '&trans')

### functions
top = ['&trans'] + [f'&kp F{i}' for i in range(7,11)] + ['&trans'] * 4 + ['&kp C_VOL_UP']
middle = ['&trans'] + [f'&kp F{i}' for i in range(4,7)] + ['&kp F11' ] + ['&trans'] * 4 + ['&kp C_MUTE']
bottom = ['&trans'] + [f'&kp F{i}' for i in range(1,4)] + ['&kp F12', '&trans', '&trans', '&trans', '&trans', '&kp C_VOL_DN']
thumb[1] = '&bt BT_CLR'
function_layer = makelayer('function_layer', top, middle, bottom, thumb, '&trans')

### put it all together
# layers = '#+begin_src text :tangle ~/code/sweep-zmk/config/cradio.keymap\n'
layers += f'keymap {{\n\n  compatible = "zmk,keymap"; \n\n  {default_layer} \n\n  {number_layer} \n\n  {function_layer}\n}};'
layers += '};' # the last bracket to close the root object
return layers

TODO 故障かなと思ったとき

https://docs.splitkb.com/hc/en-us/articles/360010552339-One-or-more-keys-don-t-work

どうも右の’c’キーが効かない。あとで試してみよう。日本語では使われ無いのを知る。

Date: 2022-11-10 Thu 10:21