⌨️
45%キーボードの製作メモ
1.はじめに
約45%のキーボードを設計・製作したので、概要を書いてみます。
キーボードの名前は「kplj50」です。
(45%と言いつつキー数は50です。サイズ的に、15u×5行が60%だから、14u×4行は45%かなと。)
作ったもの
- 一体型の60%キーボードから数字の行をなくして、両端のキーを0.5uずつ小さくしたサイズのキーボードです。
- ケースは、ステンレスプレートのサンドイッチにしました。
- ProMicroを使用しました。
製作動機
前回50%キーボードを作った後、ProMicroの裏表を変えてもう少し薄くしたい、丁度いいスカルプチャードのキーキャップがあれば左右0.5uずつ小さくしたいと思っていました。
そんなとき、AmazonでXVXプロファイルの189キーのキーキャップを見つけて、左右0.5u詰めたレイアウトが出来そうだったので、また作ることにしました。
2.キーレイアウト
このようにしました。
_BASEレイヤー
- 普段の文字入力用です。
_NUMレイヤー
- 数字・記号の入力用です。
-
変換
と無変換
の同時ホールド またはMy_Caps
をホールドしている間、ONにします。 -
My_Caps
ダブルタップ、シングルタップでトグルさせます。
(数字のレイヤー切り替えは未だ迷走中です。)
_CURSORレイヤー
- vi風カーソル、各種移動、右クリメニュー、よく使うファンクションキー用です。
-
変換
または無変換
のどちらかをホールドしている間、ONにします。 -
Fn
ダブルタップ、シングルタップでトグルさせます。
_FUNCレイヤー
- ファンクションキー入力用です。
-
変換
または無変換
を押しながら、My_Caps
をホールドしている間、ONにします。 - また、
変換
または無変換
を押しながらMy_Caps
ダブルタップでON継続、My_Caps
シングルタップでOFFにします。
_FUNC2レイヤー
- 音量と液晶の明るさなどのキー入力用です。
-
Fn
をホールドしている間、ONにします。
3.設計
- 今回はProMicroをEnterキーの裏側につけることにしました。
- PCBの背面側で、外からLEDが見える向きです。
キーのRow,Colの割り付け
- まずはキーマップのRow,Colを割り付けて、回路図を作成しました。
- PCBエディタで配線するときに、なるべくつなぎやすいようにProMicroのピン割り付けを調整しました。
- 図の①②は、ダイオードにつなぐ方のSWのピン番号です。
回路図
BPC
- 14u x 4行ピッタリのサイズです。(19.05mmの14x4)
プレート
- PCBと同じサイズです。
- いずれも厚さ1.5mmです。
スペーサ
-
スイッチプレートとPCBの間に入れようと思って設計しました。
-
取り付けが接着剤なのと、思ったより見栄えがイマイチだったので、なくても良かったです。
-
こちらは、PCBとボトムプレートの間に入れようと思って設計しました。
-
2mmで設計したものの、組立時に3mm欲しかったことがわかり、このパーツは使いませんでした。
qmk
- 英語配列です。
- OS側は日本語キーボードの設定から変えない前提で、key_overrideで置き換えます。
- タップダンスは、
Fn
,Alt
,My_Caps
,チルダ
で使いました。
keymap.c
#include QMK_KEYBOARD_H
#include "keymap_japanese.h"
// pushed記憶用
static bool b_mhen = false;
static bool b_henk = false;
static bool b_caps = false;
static bool b_rsft = false;
static bool b_lsft = false;
static bool b_tg_fnc = false; // _FUNCレイヤーにトグル中
typedef enum {
TD_NONE,
TD_UNKNOWN,
TD_SINGLE_TAP,
TD_SINGLE_HOLD,
TD_DOUBLE_TAP,
TD_DOUBLE_HOLD,
TD_DOUBLE_SINGLE_TAP,
TD_TRIPLE_TAP,
TD_TRIPLE_HOLD
} td_state_t;
typedef struct {
bool is_press_action;
td_state_t state;
} td_tap_t;
typedef struct {
bool is_press_action;
td_state_t state;
bool shifted;
} td_tap2_t;
enum {
TD_FN,
TD_LALT,
TD_RALT,
TD_GRV,
TD_CAPS
};
enum my_keycodes {
MY_CAPS = SAFE_RANGE,
};
enum layers {
_BASE = 0,
_NUM,
_CURSOR,
_FUNC,
_FUNC2
};
// -------------------------------------------------------------------------
// タップダンス
// interruptedをタップとみなす
td_state_t cur_dance(qk_tap_dance_state_t *state) {
switch (state->count) {
case 1: {
if (state->interrupted || !state->pressed) return TD_SINGLE_TAP;
else return TD_SINGLE_HOLD;
} break;
case 2: {
if (state->interrupted) return TD_DOUBLE_SINGLE_TAP;
else if (state->pressed) return TD_DOUBLE_HOLD;
else return TD_DOUBLE_TAP;
} break;
case 3: {
if (state->interrupted || !state->pressed) return TD_TRIPLE_TAP;
else return TD_TRIPLE_HOLD;
} break;
default: return TD_UNKNOWN;
}
}
// interruptedをホールドとみなす
td_state_t cur_dance2(qk_tap_dance_state_t *state) {
switch (state->count) {
case 1: {
if (!state->interrupted && !state->pressed) return TD_SINGLE_TAP;
else return TD_SINGLE_HOLD;
} break;
case 2: {
if (!state->interrupted && !state->pressed) return TD_DOUBLE_TAP;
else return TD_DOUBLE_HOLD;
} break;
case 3: {
if (!state->interrupted && !state->pressed) return TD_TRIPLE_TAP;
else return TD_TRIPLE_HOLD;
} break;
default: return TD_UNKNOWN;
}
}
// タップダンス用の td_tap_t のインスタンス
// Fnキー
static td_tap_t fn_tap_state = {
.is_press_action = true,
.state = TD_NONE
};
// LAltキー
static td_tap_t lalt_tap_state = {
.is_press_action = true,
.state = TD_NONE
};
// RAltキー
static td_tap_t ralt_tap_state = {
.is_press_action = true,
.state = TD_NONE
};
// CapsLockキー
static td_tap_t caps_tap_state = {
.is_press_action = true,
.state = TD_NONE
};
// グレイブ、チルダ
static td_tap2_t grv_tap_state = {
.is_press_action = true,
.state = TD_NONE,
.shifted = false
};
// -------------------------------------------------------------------------
// タップダンスの処理
// Fnキー
// Single Tap: _BASEレイヤー
// Double Tap: _CURSORレイヤー
// Hold : _FUNC2レイヤー
void fn_finished(qk_tap_dance_state_t *state, void *user_date) {
fn_tap_state.state = cur_dance2(state);
switch (fn_tap_state.state) {
case TD_SINGLE_TAP:{
layer_off(_CURSOR);
layer_off(_NUM);
layer_off(_FUNC);
layer_off(_FUNC2);
} break;
case TD_SINGLE_HOLD:
case TD_DOUBLE_HOLD:
case TD_TRIPLE_HOLD: {
layer_off(_CURSOR);
layer_off(_NUM);
layer_off(_FUNC);
layer_on(_FUNC2);
} break;
case TD_DOUBLE_TAP:
case TD_DOUBLE_SINGLE_TAP:
case TD_TRIPLE_TAP: {
layer_on(_CURSOR);
layer_off(_NUM);
layer_off(_FUNC);
layer_off(_FUNC2);
} break;
default: break;
}
fn_tap_state.state = TD_NONE;
}
void fn_reset(qk_tap_dance_state_t *state, void *user_date) {
switch (lalt_tap_state.state) {
case TD_SINGLE_HOLD:
case TD_DOUBLE_HOLD:
case TD_TRIPLE_HOLD: {
layer_off(_CURSOR);
layer_off(_NUM);
layer_off(_FUNC);
layer_off(_FUNC2);
} break;
default: break;
}
fn_tap_state.state = TD_NONE;
}
// --------------------------------------
// LAltキー
// Double Hold: Alt + 数字用
void lalt_finished(qk_tap_dance_state_t *state, void *user_date) {
lalt_tap_state.state = cur_dance2(state);
switch (lalt_tap_state.state) {
case TD_SINGLE_TAP:
case TD_SINGLE_HOLD:
case TD_DOUBLE_TAP:
case TD_DOUBLE_SINGLE_TAP:
case TD_TRIPLE_TAP: register_code(KC_LALT); break;
case TD_DOUBLE_HOLD:
case TD_TRIPLE_HOLD: {
layer_on(_NUM);
register_code(KC_LALT);
} break;
default: break;
}
}
void lalt_reset(qk_tap_dance_state_t *state, void *user_date) {
switch (lalt_tap_state.state) {
case TD_SINGLE_TAP:
case TD_SINGLE_HOLD:
case TD_DOUBLE_TAP:
case TD_DOUBLE_SINGLE_TAP:
case TD_TRIPLE_TAP: unregister_code(KC_LALT); break;
case TD_DOUBLE_HOLD:
case TD_TRIPLE_HOLD: {
layer_off(_NUM);
unregister_code(KC_LALT);
} break;
default: break;
}
lalt_tap_state.state = TD_NONE;
}
// --------------------------------------
// RAltキー
// Double Hold: Alt + 数字用
void ralt_finished(qk_tap_dance_state_t *state, void *user_date) {
ralt_tap_state.state = cur_dance2(state);
switch (ralt_tap_state.state) {
case TD_SINGLE_TAP:
case TD_SINGLE_HOLD:
case TD_DOUBLE_TAP:
case TD_DOUBLE_SINGLE_TAP:
case TD_TRIPLE_TAP: register_code(KC_RALT); break;
case TD_DOUBLE_HOLD:
case TD_TRIPLE_HOLD: {
layer_on(_NUM);
register_code(KC_RALT);
} break;
default: break;
}
}
void ralt_reset(qk_tap_dance_state_t *state, void *user_date) {
switch (ralt_tap_state.state) {
case TD_SINGLE_TAP:
case TD_SINGLE_HOLD:
case TD_DOUBLE_TAP:
case TD_DOUBLE_SINGLE_TAP:
case TD_TRIPLE_TAP: unregister_code(KC_RALT); break;
case TD_DOUBLE_HOLD:
case TD_TRIPLE_HOLD: {
layer_off(_NUM);
unregister_code(KC_RALT);
} break;
default: break;
}
ralt_tap_state.state = TD_NONE;
}
// --------------------------------------
// CapsLockキー
// Single Hold: _NUMレイヤー (*)
// Double Hold: Shift + _NUMレイヤー (*)
// Single Tap : _BASEレイヤーにトグル
// Double Tap : _NUMレイヤーにトグル (*)
// *) 変換or無変換と組合せのときは_FUNCレイヤー
void caps_finished(qk_tap_dance_state_t *state, void *user_date) {
caps_tap_state.state = cur_dance2(state);
switch (caps_tap_state.state) {
case TD_SINGLE_TAP: {
if (!b_mhen && !b_henk) {
layer_off(_NUM);
layer_off(_FUNC);
layer_off(_CURSOR);
}
b_tg_fnc=false;
} break;
case TD_DOUBLE_TAP:
case TD_TRIPLE_TAP: {
if (!b_mhen && !b_henk) {
layer_on(_NUM);
layer_off(_FUNC);
b_tg_fnc=false;
} else {
layer_off(_NUM);
layer_on(_FUNC);
b_tg_fnc=true;
}
} break;
case TD_SINGLE_HOLD: {
if (!b_mhen && !b_henk) {
layer_on(_NUM);
layer_off(_FUNC);
} else {
layer_off(_NUM);
layer_on(_FUNC);
}
b_tg_fnc=false;
} break;
case TD_DOUBLE_HOLD:
case TD_TRIPLE_HOLD: {
register_code(KC_RSFT);
if (!b_mhen && !b_henk) {
layer_on(_NUM);
layer_off(_FUNC);
} else {
layer_off(_NUM);
layer_on(_FUNC);
}
b_tg_fnc=false;
} break;
default: {b_tg_fnc=false;} break;
}
}
void caps_reset(qk_tap_dance_state_t *state, void *user_date) {
switch (caps_tap_state.state) {
case TD_DOUBLE_TAP:
case TD_TRIPLE_TAP: {
unregister_code(KC_RSFT);
} break;
case TD_SINGLE_HOLD: {
if (b_mhen && b_henk) {
layer_on(_NUM);
layer_off(_CURSOR);
layer_off(_FUNC);
} else if (b_mhen || b_henk) {
layer_off(_NUM);
layer_on(_CURSOR);
layer_off(_FUNC);
} else {
layer_off(_NUM);
layer_off(_CURSOR);
layer_off(_FUNC);
}
} break;
case TD_DOUBLE_HOLD:
case TD_TRIPLE_HOLD: {
unregister_code(KC_RSFT);
if (b_mhen && b_henk) {
layer_on(_NUM);
layer_off(_CURSOR);
layer_off(_FUNC);
} else if (b_mhen || b_henk) {
layer_off(_NUM);
layer_on(_CURSOR);
layer_off(_FUNC);
} else {
layer_off(_NUM);
layer_off(_CURSOR);
layer_off(_FUNC);
}
} break;
default: break;
}
b_caps = false;
caps_tap_state.state = TD_NONE;
}
void caps_each_tap(qk_tap_dance_state_t *state, void *user_date) {
switch (state->count) {
case 1: {
b_caps = true;
if (!b_mhen && !b_henk) {
layer_on(_NUM);
layer_off(_FUNC);
} else {
layer_off(_NUM);
layer_on(_FUNC);
}
} break;
case 2: {
b_caps = true;
register_code(KC_RSFT);
} break;
default: b_caps = true; break;
}
}
// --------------------------------------
// グレイブ
void grv_finished(qk_tap_dance_state_t *state, void *user_date) {
grv_tap_state.state = cur_dance(state);
switch (grv_tap_state.state) {
case TD_SINGLE_TAP: {
if (!grv_tap_state.shifted) {
register_code(KC_LSFT);
tap_code(KC_LBRC);
unregister_code(KC_LSFT);
} else {
register_code(KC_LSFT);
tap_code(KC_EQL);
if (!b_lsft) unregister_code(KC_LSFT);
}
} break;
case TD_DOUBLE_TAP:
case TD_DOUBLE_SINGLE_TAP:
case TD_TRIPLE_TAP: {
register_code(KC_LSFT);
tap_code(KC_EQL);
unregister_code(KC_LSFT);
} break;
default: break;
}
}
void grv_reset(qk_tap_dance_state_t *state, void *user_date) {
grv_tap_state.state = TD_NONE;
grv_tap_state.shifted = false;
}
void grv_each_tap(qk_tap_dance_state_t *state, void *user_date) {
grv_tap_state.shifted = (b_rsft || b_lsft);
}
// -------------------------------------------------------------------------
// タップダンスのアクションの設定
qk_tap_dance_action_t tap_dance_actions[] = {
[TD_FN] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, fn_finished, fn_reset),
[TD_LALT] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, lalt_finished, lalt_reset),
[TD_RALT] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, ralt_finished, ralt_reset),
[TD_CAPS] = ACTION_TAP_DANCE_FN_ADVANCED(caps_each_tap, caps_finished, caps_reset),
[TD_GRV] = ACTION_TAP_DANCE_FN_ADVANCED(grv_each_tap, grv_finished, grv_reset),
};
#define TDD_FN TD(TD_FN)
#define TDD_LALT TD(TD_LALT)
#define TDD_RALT TD(TD_RALT)
#define TDD_CAPS TD(TD_CAPS)
#define TDD_GRV TD(TD_GRV)
// -------------------------------------------------------------------------
#define TO_BASE TO(_BASE)
#define NUM_ENT LT(_NUM, KC_ENT)
// shift+2 " -> @
const key_override_t kor_at = ko_make_with_layers(MOD_MASK_SHIFT, KC_2, JP_AT, ~0);
// shift+6 & -> ^
const key_override_t kor_circ = ko_make_with_layers(MOD_MASK_SHIFT, KC_6, JP_CIRC, ~0);
// shift+7 ' -> &
const key_override_t kor_ampr = ko_make_with_layers(MOD_MASK_SHIFT, KC_7, JP_AMPR, ~0);
// shift+8 ( -> *
const key_override_t kor_astr = ko_make_with_layers(MOD_MASK_SHIFT, KC_8, JP_ASTR, ~0);
// shift+9 ) -> (
const key_override_t kor_lprn = ko_make_with_layers(MOD_MASK_SHIFT, KC_9, JP_LPRN, ~0);
// shift+0 -> )
const key_override_t kor_rprn = ko_make_with_layers(MOD_MASK_SHIFT, KC_0, JP_RPRN, ~0);
// shift+- = -> _
const key_override_t kor_unds = ko_make_with_layers(MOD_MASK_SHIFT, KC_MINS, JP_UNDS, ~0);
// = ^ -> =
// shift+= ~ -> +
const key_override_t kor_eql = ko_make_with_layers_and_negmods(0, JP_CIRC, JP_EQL, ~0, MOD_MASK_SHIFT);
const key_override_t kor_plus = ko_make_with_layers(MOD_MASK_SHIFT, JP_CIRC, JP_PLUS, ~0);
/* \ ] -> \ */
/* shift+\ } -> | */
const key_override_t kor_bsls = ko_make_with_layers_and_negmods(0, KC_BSLS, JP_BSLS, ~0, MOD_MASK_SHIFT);
const key_override_t kor_pipe = ko_make_with_layers(MOD_MASK_SHIFT, KC_BSLS, JP_PIPE, ~0);
// [ @ -> [
// shift+[ ` -> {
const key_override_t kor_lbrc = ko_make_with_layers_and_negmods(0, JP_AT, JP_LBRC, ~0, MOD_MASK_SHIFT);
const key_override_t kor_lcbr = ko_make_with_layers(MOD_MASK_SHIFT, JP_AT, JP_LCBR, ~0);
// ] [ -> ]
// shift+] { -> }
const key_override_t kor_rbrc = ko_make_with_layers_and_negmods(0, JP_LBRC, JP_RBRC, ~0, MOD_MASK_SHIFT);
const key_override_t kor_rcbr = ko_make_with_layers(MOD_MASK_SHIFT, JP_LBRC, JP_RCBR, ~0);
// shift+; + -> :
const key_override_t kor_coln = ko_make_with_layers(MOD_MASK_SHIFT, KC_SCLN, JP_COLN, ~0);
// ' : -> '
// shift+' * -> "
const key_override_t kor_quot = ko_make_with_layers_and_negmods(0, KC_QUOT, JP_QUOT, ~0, MOD_MASK_SHIFT);
const key_override_t kor_dquo = ko_make_with_layers(MOD_MASK_SHIFT, KC_QUOT, JP_DQUO, ~0);
// ` 全角半角 -> `
// shift+` shift+全角半角 -> ~
const key_override_t kor_grv = ko_make_with_layers_and_negmods(0, KC_GRV, JP_GRV, ~0, MOD_MASK_SHIFT);
const key_override_t kor_tild = ko_make_with_layers(MOD_MASK_SHIFT, KC_GRV, JP_TILD, ~0);
const key_override_t **key_overrides = (const key_override_t *[]){
&kor_at,
&kor_circ,
&kor_ampr,
&kor_astr,
&kor_lprn,
&kor_rprn,
&kor_unds,
&kor_eql,
&kor_plus,
&kor_bsls,
&kor_pipe,
&kor_lbrc,
&kor_lcbr,
&kor_rbrc,
&kor_rcbr,
&kor_coln,
&kor_quot,
&kor_dquo,
&kor_grv,
&kor_tild,
NULL
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* _BASE
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW1 SW2 SW3 SW4 SW5 SW6 SW7 SW8 SW9 SW10 SW11 SW12 SW13 SW14
* Tab Q W E R T Y U I O P -_ =+ BS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW15 SW16 SW17 SW18 SW19 SW20 SW21 SW22 SW23 SW24 SW25 SW26 SW27
* TD_CAPS A S D F G H J K L ;: '" Enter
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW28 SW29 SW30 SW31 SW32 SW33 SW34 SW35 SW36 SW37 SW38 SW39
* LShift Z X C V B N M ,< .> /? RShift
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW40 SW41 SW42 SW43 SW44 SW45 SW46 SW47 SW48 SW49 SW50
* LCtrl Win TD_LAlt Muhen Space RCtrl Henkan TD_RAlt Kana TD_FN RCtrl
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
*/
[_BASE] = LAYOUT_1(
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_MINS, KC_EQL, KC_BSPC,
// TDD_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, NUM_ENT,
TDD_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT,
KC_LCTL, KC_LGUI, TDD_LALT, JP_MHEN, KC_SPC, KC_RCTL, JP_HENK, TDD_RALT, JP_KANA, TDD_FN, KC_RCTL
),
/*****************************************************************************************************************************************************
* _NUM
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW1 SW2 SW3 SW4 SW5 SW6 SW7 SW8 SW9 SW10 SW11 SW12 SW13 SW14
* Tab 1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) -_ =+ BS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW15 SW16 SW17 SW18 SW19 SW20 SW21 SW22 SW23 SW24 SW25 SW26 SW27
* TRNS Left Down Up Right ;: '" Enter
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW28 SW29 SW30 SW31 SW32 SW33 SW34 SW35 SW36 SW37 SW38 SW39
* TRNS TO_BASE Enter ,< .> /? TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW40 SW41 SW42 SW43 SW44 SW45 SW46 SW47 SW48 SW49 SW50
* TRNS TRNS TRNS TRNS TRNS TRNS TRNS INS TRNS TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
*/
[_NUM] = LAYOUT_1(
KC_TAB, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC,
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, _______, _______, _______,
_______, TO_BASE, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_ENT, KC_COMM, KC_DOT, KC_SLSH, _______,
_______, XXXXXXX, _______, _______, _______, _______, _______, _______, JP_EISU, _______, _______
),
/*****************************************************************************************************************************************************
* _CURSOR
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW1 SW2 SW3 SW4 SW5 SW6 SW7 SW8 SW9 SW10 SW11 SW12 SW13 SW14
* ESC `~ F2 F3 F4 F5 SCRLOCK PgUp PgDwn [{ ]} DEL
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW15 SW16 SW17 SW18 SW19 SW20 SW21 SW22 SW23 SW24 SW25 SW26 SW27
* TRNS App Left Down Up Right ;: '" Enter
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW28 SW29 SW30 SW31 SW32 SW33 SW34 SW35 SW36 SW37 SW38 SW39
* TRNS TO_BASE Caps Enter Home End \| TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW40 SW41 SW42 SW43 SW44 SW45 SW46 SW47 SW48 SW49 SW50
* TRNS TRNS TRNS TRNS TRNS TRNS Eisu TRNS TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
*/
[_CURSOR] = LAYOUT_1(
KC_ESC, TDD_GRV, KC_F2, KC_F3, KC_F4, KC_F5, XXXXXXX, KC_SLCK, KC_PGUP, KC_PGDN, XXXXXXX, KC_LBRC, KC_RBRC, KC_DEL,
_______, KC_APP, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, _______, _______, _______,
_______, TO_BASE, XXXXXXX, JP_CAPS, XXXXXXX, XXXXXXX, XXXXXXX, KC_ENT, KC_HOME, KC_END, KC_BSLS, _______,
_______, XXXXXXX, _______, _______, _______, _______, _______, _______, JP_EISU, _______, _______
),
/*****************************************************************************************************************************************************
* _FUNC
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW1 SW2 SW3 SW4 SW5 SW6 SW7 SW8 SW9 SW10 SW11 SW12 SW13 SW14
* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW15 SW16 SW17 SW18 SW19 SW20 SW21 SW22 SW23 SW24 SW25 SW26 SW27
* TRNS TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW28 SW29 SW30 SW31 SW32 SW33 SW34 SW35 SW36 SW37 SW38 SW39
* TRNS TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW40 SW41 SW42 SW43 SW44 SW45 SW46 SW47 SW48 SW49 SW50
* TRNS TRNS TRNS TRNS TRNS TRNS TRNS TRNS TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
*/
[_FUNC] = LAYOUT_1(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, XXXXXXX,
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, _______,
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, _______,
_______, XXXXXXX, _______, _______, _______, _______, _______, _______, XXXXXXX, _______, _______
),
/*****************************************************************************************************************************************************
* _FUNC2
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW1 SW2 SW3 SW4 SW5 SW6 SW7 SW8 SW9 SW10 SW11 SW12 SW13 SW14
* ESC Mute VolDwn VolUp INS PSCREEN PAUSE
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW15 SW16 SW17 SW18 SW19 SW20 SW21 SW22 SW23 SW24 SW25 SW26 SW27
* TRNS BriDwn BriUp TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW28 SW29 SW30 SW31 SW32 SW33 SW34 SW35 SW36 SW37 SW38 SW39
* TRNS TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
* SW40 SW41 SW42 SW43 SW44 SW45 SW46 SW47 SW48 SW49 SW50
* TRNS TRNS TRNS TRNS TRNS TRNS TRNS TRNS TRNS
* +---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+
*/
[_FUNC2] = LAYOUT_1(
KC_ESC, XXXXXXX, KC_MUTE, KC_VOLD, KC_VOLU, XXXXXXX, XXXXXXX, XXXXXXX, KC_INS, XXXXXXX, KC_PSCR, XXXXXXX, XXXXXXX, KC_PAUS,
_______, XXXXXXX, XXXXXXX, KC_BRID, KC_BRIU, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, _______,
_______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, _______,
_______, XXXXXXX, _______, _______, _______, _______, _______, _______, XXXXXXX, _______, _______
)
};
static uint16_t pressed_henk_time = 0;
static uint16_t pressed_mhen_time = 0;
static uint16_t mem_keycode = 0;
bool process_record_user(uint16_t keycode, keyrecord_t *record){
uint16_t prev_keycode = mem_keycode;
bool is_tapped = ((!record->event.pressed) && (keycode == prev_keycode));
mem_keycode = keycode;
switch (keycode) {
case JP_MHEN: {
if (record->event.pressed) { // 無変換を押した
b_mhen = true;
pressed_mhen_time = record->event.time;
if (b_henk) {
layer_on(_NUM); // 変換も押されていれば _NUM on, _CURSOR off
layer_off(_CURSOR);
} else if (b_caps) {
layer_on(_FUNC); // 変換は押されていなくて、Capsが押されているときは _FUNC on
} else {
layer_on(_CURSOR); // 変換もCapsも押されていない _CURSOR on
}
}
else { // 無変換を離した
b_mhen = false;
if (b_henk) {
layer_off(_NUM); // 変換が押されたままなら _NUM off, _CURSOR on
layer_on(_CURSOR);
} else {
layer_off(_CURSOR); // 変換が押されていないなら _CURSOR off
if (b_caps) {
layer_on(_NUM); // Capsが押されているなら _NUM on
} else if (!b_tg_fnc) {
layer_off(_FUNC); // Capsが押されていないくて、_FUNCにトグル中でないなら、_FUNC off
}
}
if (is_tapped && (TIMER_DIFF_16(record->event.time, pressed_mhen_time) <= TAPPING_TERM)) {
tap_code(keycode); // タップなら無変換
}
}
return false;
} break;
case JP_HENK: {
if (record->event.pressed) { // 変換を押した
b_henk = true;
pressed_henk_time = record->event.time;
if (b_mhen) {
layer_on(_NUM); // 無変換も押されていれば _NUM on, _CURSOR off
layer_off(_CURSOR);
} else if (b_caps) {
layer_on(_FUNC); // 無変換は押されていなくて、Capsが押されているときは _FUNC on
} else {
layer_on(_CURSOR); // 無変換もCapsも押されていない _CURSOR on
}
}
else { // 変換を離した
b_henk = false;
if (b_mhen) {
layer_off(_NUM); // 無変換が押されたままなら _NUM off, _CURSOR on
layer_on(_CURSOR);
} else {
layer_off(_CURSOR); // 無変換が押されていないなら _CURSOR off
if (b_caps) {
layer_on(_NUM); // Capsが押されているなら _NUM on
} else if (!b_tg_fnc) {
layer_off(_FUNC); // Capsが押されていないくて、_FUNCにトグル中でないなら、_FUNC off
}
}
if (is_tapped && (TIMER_DIFF_16(record->event.time, pressed_henk_time) <= TAPPING_TERM)) {
tap_code(keycode); // タップなら変換
}
}
return false;
} break;
case KC_RSFT: {
if (record->event.pressed) {
b_rsft = true;
} else {
b_rsft = false;
}
return true;
} break;
case KC_LSFT: {
if (record->event.pressed) {
b_lsft = true;
} else {
b_lsft = false;
}
return true;
} break;
default: {
} break;
}
return true;
}
4.発注
PCB
今回もFusionPCBを利用しました。
ステンレスプレート
切断堂さんを利用しました。
ステンレス/SUS304-HLのオーダーカットです。
アクリルよりもかなり強度と重量感があり、とても気に入りました。
アクリルスペーサ
遊舎工房さんのアクリル加工サービスを利用しました。
5.製作
主要パーツ
組み立てる前のPCB、ステンレスプレート、アクリルスペーサです。
PCBはんだ付け
- ProMicroのピンヘッダは、ProMicroの外側にあまり出ないように、ペンチで切って短くしました。
- ここで重大な失敗に気づきました。
- ProMicroのフットプリントを裏表ひっくり返して使ったのですが、片方にシルク印刷があったのを見逃しました。もとはピンヘッダ側にあったシルク印刷が、ひっくり返したことで、はんだ付けする面に来てしまいました。
- ただ、はんだ付けをやってみたらスルーホールの中の方にハンダがしみ込んでくれて、なんとか付きました。
組み立て
- スイッチプレートにM2の平ネジで真鍮のスペーサをつけます。
- PCBは、3mmの真鍮スペーサと0.5mmのナイロンワッシャーを介して、スイッチプレートと固定します。
- ボトムプレートは、7mmの真鍮スペーサと1mmのナイロンワッシャーを介して、スイッチプレートと固定します。PCBは貫通です。1mmのナイロンワッシャーは当初はスイッチプレート側だけで考えていたのですが、ProMicroが少しはみ出たので、ボトムプレート側にもはさみました。
- スイッチプレート、PCB、ボトムプレートのネジ止め後。
- ネジについている黒いのは、緩み防止のつもりの金属用接着剤です。
- スイッチ取り付け後。
- Gateronの静音赤軸(45g)と静音クリア軸(35g)の混在です。小指で押すキーとホームポジションから離れたキーは35gにしました。
- キースイッチの潤滑は、Amazonで見つけたエーゼットのシリコーングリースを使いました。
- ルブよりも粘度があるように感じました。
- ボトムプレートにProMicro用のアクリルカバーをつけた後。
- カバーの取り付けは皿ネジです。皿穴は、プラモ用の皿モミ工具で加工しています。
- 右側は、高さを揃えるためのダミーです。
- ProMicroの表面実装部品2個がぶつかってしまったので、穴を開けてしのぎました。
- アクリルカバーは、ネジだけだと取り付けが弱そうだったので、接着剤でくっつけました。
- 当初はアクリルカバーの上に足を付けようとしたのですが、壊れそうな気がしたので内側のステンレス部分につけました。
6.終わりに
今回はProMicroのはんだ付けする面にシルク印刷をしてしまったのが悔やまれます。
次にまたProMicroで作ることがあれば、気をつけたいと思います。
(できれば、PCBに直接ATmega32u4を実装したい。)
Discussion