포스트

ZMK 키맵 설계기 — HHKB + 40% + 세벌식 390, 그리고 실수로 안 눌리게 만들기

40% 키보드 키맵을 세벌식 390과 HHKB 손버릇에 맞춰 설계하고, 부트로더·화면 슬립처럼 위험한 키를 hold-tap으로 실수 방지하는 방법을 정리합니다.

ZMK 키맵 설계기 — HHKB + 40% + 세벌식 390, 그리고 실수로 안 눌리게 만들기

관련 시리즈: 키보드 로드맵 · 세벌식 390 입문 · HHKB 입문

ZMK로 40% 키보드 키맵을 짜다 보면 결국 “왜 이 키를 여기에 뒀는가”가 전부다. 물리 키가 적으니 레이어와 배치 하나하나가 손버릇·입력기·용도에 맞물린다. 이 글은 HHKB 손버릇 + 40% 물리 배열 + 세벌식 390 입력이라는 세 제약을 키맵에 녹인 과정과, 부트로더처럼 눌리면 곤란한 키를 hold-tap으로 실수 방지하는 기법을 정리한 것이다.

덧붙이면, “40% 키보드에서 세벌식 390을 쓴” 사례는 찾아본 한도에서는 거의 없었다. 두벌식용 40% 세팅이나 세벌식 데스크톱 세팅은 있어도, 이 둘을 겹친 조합은 좀처럼 안 보인다. 그래서 이 글은 선례가 드문 조합을 직접 아이디어 내서 만든 뒤 기록해두는 성격도 있다 — 같은 길을 가려는 누군가에게 출발점이 되길 바란다.

사실 “세벌식 390은 숫자열을 한글에 써서 40% 키보드와 안 맞는다”는 문제를 물어보면, 흔히 돌아오는 답은 “숫자열을 한글에 쓰지 않는 배열로 바꿔라”였다. 하지만 나는 390의 넘패드식 숫자 입력(뒤에서 설명한다)을 계속 쓰고 싶었다. 그래서 배열을 포기하는 대신 키보드 펌웨어 쪽에서 푸는 길을 택했고, 이 글의 number 레이어 설계가 그 결과다. 직접 짜서 지금까지 아주 잘 쓰고 있다.

예시는 ZMK 기준이지만, 레이어 설계·hold-tap 아이디어는 QMK 등 다른 펌웨어에도 그대로 옮겨갈 수 있다.

설계 제약 세 가지

  • HHKB: CtrlA 왼쪽(Caps 자리)에 두고, 방향키는 Fn 레이어로 집고, 백스페이스를 우상단에 두는 미니멀 배열. 특히 좌 Ctrl 위치와 Fn+방향키가 몸에 배어 있다.
  • 40%: 숫자·기호·방향키를 물리 키가 아니라 레이어로 분리.
  • 세벌식 390: OS 입력기로 한글을 치되, 그 위에서 물리 배열·기호·레이어를 취향에 맞춤.

이 세 개가 맞물리면서 키맵의 “왜”가 자연스럽게 결정된다.

세벌식 390이 숫자 레이어를 강제한다

세벌식 390의 핵심 특징 하나: 숫자열(1~0)을 한글 자모 입력에 쓴다. 즉 기본 상태에서 상단 숫자열은 숫자가 아니라 한글이 나온다. 그러면 숫자를 치려면 별도의 방법이 필요하다.

그래서 40% 키맵에서 흔히 쓰는 “number 레이어”가 여기선 선택이 아니라 필연이 된다. 숫자를 되찾아주는 전용 레이어를 두고, 상단에 1~0을 그대로 깐다.

1
2
3
4
number 레이어
Tab   1    2    3    4    5      6    7    8    9    0    ·    ▽
Caps  ·    ·    ·    ·    ·      ·    4    5    6    ·    ▽
▽     ·    ·    ·    ·    ·      0    1    2    3    ▽    ▽

오른손(H J K L / N M , .)에는 넘패드처럼 4 5 6 / 0 1 2 3을 겹쳐 둔다. 이건 사실 세벌식 390에서 온 습관이다. 세벌식 390은 숫자를 넘패드(숫자 키패드)와 똑같은 배열로 입력하도록 되어 있어서, 세벌식을 쓰다 보면 숫자를 넘패드처럼 3×3 그리드로 집는 감각이 몸에 밴다. 그 감각을 number 레이어의 넘패드로 그대로 옮긴 것이다.

접근키를 두 개 둔다

숫자를 자주 꺼내야 하니 number 레이어 진입키의 접근성이 중요하다. 그래서 전환키를 두 곳에 둔다.

  • 왼쪽 스페이스를 layer-tap으로: 탭하면 Space, 홀드하면 number 레이어(&lt 1 SPACE). 타이핑 중 손을 떼지 않고 숫자에 진입.
  • 우하단 Fn 자리에 momentary(&mo 1): HHKB의 Fn 위치 그대로.
// 왼쪽 스페이스 = 탭:Space / 홀드:number 레이어
&lt 1 SPACE

“세벌식이 숫자열을 한글에 뺏김 → 숫자 전용 레이어 필요 → 자주 쓰니 스페이스 홀드로 빠른 접근”까지, 하나의 제약이 배치를 연쇄적으로 결정한다.

기호는 오른쪽 열에 몰아 둔다

특수문자용 레이어(specialA, specialB)는 기호를 오른쪽 열에 집중시켰다. 일반 키보드에서 -, =, [, ], \, ;, ', ,, ., / 같은 기호를 우측 열부터 오른손으로 집던 감각을 그대로 유지하기 위해서다.

1
2
3
4
specialA 레이어
▽    ·    ·    ·    ·    ·      ·    ·    ·    ·    [    ]    ▽
▽    ·    ·    ·    ·    ·      ·    ·    ·    ;    '    ▽
▽    ·    ·    ·    ·    ·      ·    ,    .    /    ▽    ▽

손이 이미 아는 위치를 레이어 위에서 재현하면 새로 외울 게 줄어든다. 40% 키맵 설계의 기본 원칙이다.

위험한 키를 hold-tap으로 감싸기

방향키 레이어에 화면 슬립 매크로와 부트로더 진입을 함께 뒀는데, 둘 다 실수로 눌리면 곤란한 키다. 화면이 갑자기 꺼지거나, 최악의 경우 부트로더로 진입해 버린다. 특히 레이어의 코너에 두면 다른 키를 누르다 스치는 일이 잦다.

해결책은 hold-tap으로 감싸서 “꾹 눌러야만” 실행되게 하는 것이다.

먼저 화면 슬립 매크로(macOS 디스플레이 슬립 = Ctrl+Shift+Power):

macros {
    screen_sleep: screen_sleep {
        compatible = "zmk,behavior-macro";
        #binding-cells = <0>;
        bindings
            = <&macro_press &kp LCTRL &kp LSHFT>
            , <&macro_tap &kp C_POWER>
            , <&macro_release &kp LCTRL &kp LSHFT>
            ;
    };
};

이 매크로를 그대로 바인딩하면 톡 스치기만 해도 실행된다. 그래서 hold-tap으로 한 겹 감싼다:

behaviors {
    // tap = 아무 동작 없음(&none), hold = screen_sleep
    screen_sleep_hold: screen_sleep_hold {
        compatible = "zmk,behavior-hold-tap";
        #binding-cells = <2>;
        flavor = "tap-preferred";
        tapping-term-ms = <300>;
        bindings = <&screen_sleep>, <&none>;
    };
    bootloader_hold: bootloader_hold {
        compatible = "zmk,behavior-hold-tap";
        #binding-cells = <2>;
        flavor = "tap-preferred";
        tapping-term-ms = <300>;
        bindings = <&bootloader>, <&none>;
    };
};

키맵에서는 이렇게 쓴다:

&screen_sleep_hold 0 0    // 짧게 = 무시, 300ms 이상 꾹 = 화면 슬립
&bootloader_hold 0 0      // 짧게 = 무시, 300ms 이상 꾹 = 부트로더

동작은 이렇게 갈린다.

  • 짧게 톡&none → 아무 일 없음. 스쳐도 안전.
  • tapping-term-ms 이상 꾹 → 실제 동작 실행.

tapping-term-ms를 300에서 400~500으로 올리면 더 확실히 막을 수 있다.

&ht 0 0처럼 파라미터를 붙이나

&bootloader나 매크로는 #binding-cells = <0>인 behavior라 원래 파라미터를 받지 않는다. 그런데 hold-tap은 &behavior param1 param2 형태로 두 개의 파라미터를 각각 hold/tap 쪽 behavior에 전달하도록 되어 있다. 그래서 0-cell behavior를 감쌀 때는 더미 파라미터 0 0을 붙인다. ZMK의 표준 패턴이다.

니모닉으로 외우기 쉽게

hold-tap 가드까지 붙였으면 위치는 자유롭게 정해도 된다(짧은 입력이 무시되니까). 자주 안 쓰는 시스템 키일수록 접근성보다 니모닉이 중요하다. 어차피 드물게 쓰니 “어디 뒀더라”가 더 큰 비용이다.

  • Z 자리 → 화면 슬립. zzz = 잠.
  • B 자리 → 부트로더. Boot.

방향키 레이어의 아래줄에 나란히 두니, 오른손 방향키 조작과도 반대편이라 스칠 일이 없고 이름도 바로 떠오른다.

함정: 레이어 정의 순서 = 레이어 인덱스

마지막으로 ZMK 초심자가 자주 밟는 함정 하나. 소스 가독성을 위해 레이어 정의 블록을 “중요도 순”으로 재배치하고 싶을 때가 있다. 그런데 ZMK에서 레이어 블록의 나열 순서는 곧 레이어 인덱스다.

arrow 블록을 위로 올려 index가 4에서 2로 바뀌면, 그 레이어를 참조하던 모든 코드가 어긋난다.

// arrow 레이어가 index 4 → 2로 이동했다면
bindings = <&mo 2>;   // combo: &mo 4 → &mo 2 로 함께 바꿔야 동작 유지

블록만 옮기면 &mo, &lt, &to 같은 레이어 참조가 엉뚱한 레이어를 가리켜 동작이 깨진다. 블록 재배치와 참조 번호 remap은 반드시 세트로 해야 한다. 반대로 말하면, 이 remap이 귀찮고 실익이 미미하다면 그냥 두는 게 낫다. 소스 순서는 취향이고 동작에는 영향이 없으니까.

정리

40% 키맵 설계에서 배운 것들:

  • 입력기 특성이 레이어를 강제한다. 세벌식 390이 숫자열을 한글에 쓰니, 숫자 전용 레이어와 빠른 접근키가 필연이 됐다.
  • 손이 이미 아는 위치를 레이어 위에서 재현하라. 기호는 오른쪽 열, 넘패드는 세벌식 390의 숫자 배열, 방향키는 HHKB Fn 손버릇 그대로.
  • 위험한 키는 hold-tap으로 감싸라. 짧게 = 무시, 꾹 = 실행. 코너에 둬도 실수 트리거가 사라진다.
  • 드문 키는 접근성보다 니모닉. Z=zzz, B=Boot.
  • 레이어 블록 순서는 인덱스다. 재배치할 땐 참조 번호도 함께.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.