리눅스에서 키맵핑하기 Ver.2 - Kanata

리눅스에서 키맵핑하기 Ver.2 - Kanata

키맵핑에 kmonad를 쓴다면서?

맞다. kmonad를 썼었다. (Kmonad 1탄Kmonad 2탄을 참고하자.) 딱 한번만 설정해두면 더 이상 건드릴 일이 없기 때문에 큰 불만은 없었다.

그러나, 딱 하나 신경쓰이는 부분이 있었으니…

엄청나게 많은 kmonad의 haskell 의존 패키지들
엄청나게 많은 kmonad의 haskell 의존 패키지들

그것은 바로, 패키지 업그레이드할 때마다 온 화면을 뒤덮는 kmonad의 haskell 의존 패키지 목록이다. 이게 참… 묘하게 신경쓰인다 말이다. 사실, kmonad가 haskell 기반이란 걸 인지하지 못했었는데, 도대체 어떤 패키지가 이렇게 많은 haskell 패키지를 쓰나 역추적하다가 이 사실을 알게 되었다.

그렇게 맘에 들지 않는 부분을 발견한 시점에 우연히 유사한 프로젝트인 kanata를 발견한 것이다. 게다가 kanata는 사용방법 측면에서 kmonad와 사실 상 거의 똑같다. 그럼에도 좀 더 좋은 점들을 가지고 있다.

그럼, 같이 kanata를 찍먹해보도록 하자.

Kanata 개요

kanata의 개발자는 kmonad 프로젝트에 기여하고 싶었으나, haskell에 대한 지식이 없었기에 별도의 rust 기반 프로젝트인 kanata를 개발했다고 한다1. 그는 kmonad로부터 영감을 받았기 때문에 .kbd 파일들을 설정하는 방식 측면에서 일부 변수들의 이름만 조금 다르고 거의 똑같다.

게다가 kanata는 1) 뛰어난 documentation을 가졌고, 2) config 파일 오류 검출 기능 면에서 더 뛰어나며, 3) 모든 OS (windows, mac, linux)에서 사용할 수 있다. 일단, 설치부터 하고 차근차근 강점들에 대해 살펴보자.

Kanata 설치

Kanata 설치는 여러 방식으로 가능하다. 다음 방식들 중 어떤 방식을 사용해도 무방하다.

  1. Source에서 직접 컴파일하기 (cargo 사용)
  2. Release 된 pre-built executable 다운받기
  3. Repo에서 컴파일된 패키지 설치하기
    [Kanata를 repo에서 지원하는 배포판들](https://repology.org/project/kanata/versions). 생각보다 그 종류가 적은 편이다.
    Kanata를 repo에서 지원하는 배포판들 . 생각보다 그 종류가 적은 편이다.

그러나 우리는 이들 중 1번 방식을 사용할 것이다. 이유가 있다. Github 의 설치 메뉴얼을 보다보면 이런 내용이 나온다.

Feature flags
When either building yourself or using cargo install, you can add feature flags that enable functionality that is turned off by default.

kanata에 슈퍼파워(?)를 부여하는 feature flag를 쓸려면 source에서 직접 빌드하란 말이다. 우리가 사용할 kanata의 슈퍼파워는 cmd 기능이다. cmd flag는 kanata를 통해 터미널 명령어들을 실행하는 단축키나 매크로를 정의할 수 있게 해준다. 안쓸 이유가 없지 않나? 그래서 우린 1번 방식을 쓰는 것이다.

자, 그럼 다음 순서를 따라 설치해보자.

cargo와 rust 설치하기

kanata는 rust로 작성되었다. 그래서 먼저 rust를 컴파일하기 위한 환경을 갖춰야 한다. rust 공식 사이트 에서 제공하는 설치 스크립트를 사용하여 cargo와 rust를 설치해주자.

bash
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

source pull 하기

cargo와 rust가 설치되었으면 kanata의 소스파일을 git pull 해주자.

bash
git clone https://github.com/jtroo/kanata $HOME/kanata

build 하기

다음 명령어를 실행하여 source 폴더로 이동 후 build 해주자.

bash
cd $HOME/kanata # kanata source 폴더로 이동
cargo build --features cmd # cmd 옵션을 추가

좋다. build가 끝났으면 $HOME/kanata/target/debug/kanata 실행파일이 생성된 것을 알 수 있다.

will@nuclearLab:~/kanata/target/debug (main)$ ls -ll                      
total 85684
drwxr-xr-x 36 will will     4096 Nov  4 18:05 build
drwxr-xr-x  2 will will    65536 Nov  4 18:05 deps
drwxr-xr-x  2 will will     4096 Nov  4 18:05 examples
drwxr-xr-x  8 will will     4096 Nov  4 18:05 incremental
-rwxr-xr-x  2 will will 65219616 Nov  4 18:05 kanata # -> 이 파일이 우리가 빌드한 kanata 실행파일이다.
-rw-r--r--  1 will will     4378 Nov  4 18:05 kanata.d
-rw-r--r--  1 will will     4197 Nov  4 18:05 libkanata_state_machine.d
-rw-r--r--  2 will will 22588528 Nov  4 18:05 libkanata_state_machine.rlib

$PATH에 build된 kanata 등록하기

개인적으로 생성한 스크립트를 저장하는 폴더가 있는가? 그러니까, PATH에 등록해두고 개인 스크립트를 저장하는 곳이 있냐는 의미다. 있으면 그 폴더에 빌드된 kanata를 복사해주자.

혹시 그런 폴더를 만들어서 사용하지 않고 있다면, 이 포스팅을 참고하여 스크립트용 경로를 만들고 PATH에 등록하는 절차를 수행하자.

필자는 $HOME/.local/bin 경로를 개인 스크립트용으로 사용하고 있다. 그래서 다음의 스크립트로 kanata를 복사해주었다.

bash
cp $HOME/kanata/target/debug/kanata $HOME/.local/bin/

앞의 kanata를 복사하고 PATH에 정상적으로 등록이 되었다면, 다음의 명령어 실행 시 kanata 경로가 출력될 것이다.

bash
which kanata

필자는 다음처럼 경로가 잘 출력되었다.

will@nuclearLab:~ $ which kanata
/home/will/.local/bin/kanata

Kanata 사용 설정하기

Keyboard configuration 파일 작성하기

kmonad의 설정 방법과 똑같다. (키보드의 고유 명칭 확인하는 절차, 원래 키배열 1개, 실제 사용할 Main 키배열 1개, 커스텀으로 사용할 배열 다수, 커스텀 배열을 toggle하는 키 설정 등)

대신, 몇몇 변수나 기능의 이름이 다를 수 있다. 그러니 kmonad 설정 포스팅을 참고하여 설정을 진행하되, kanata 메뉴얼 을 함께 보면서 변수나 기능의 이름만 적절하게 바꿔주면 된다.

설정 파일은 원하는 곳에 저장하면 되는데, 필자는 $HOME/.config/kanata 경로에 저장하였다. 최종 설정 파일(.kbd)은 다음과 같은 형태를 가지게 될 것이다.

$HOME/.config/kanata/rainy75.kbd
(defcfg
	linux-dev /dev/input/by-id/usb-RDR_Rainy_75-event-kbd
	process-unmapped-keys yes
	log-layer-changes no
	danger-enable-cmd yes
	concurrent-tap-hold yes
)

;; Variables
(defvar
	tap-time 300
	hold-time 300
	chord-time 60
)

;; Actual keyboard layout
(defsrc
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12  del   home
  grv  1    2    3    4    5    6    7    8    9    0    -    =    bspc  end
  tab  q    w    e    r    t    y    u    i    o    p    [    ]    \     pgup
  caps a    s    d    f    g    h    j    k    l    ;    '         ret   pgdn
  lsft z    x    c    v    b    n    m    ,    .    /    rsft      up
  lctl lmet lalt           spc            rctl                left down  rght
)

;; main layer
(deflayer main
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12  del   @num
  grv  1    2    3    4    5    6    7    8    9    0    -    =    bspc  end
  tab  q    w    e    r    t    y    u    i    o    p    [    ]    \     pgup
  @lyr1    a    s    d    f    g    h    j    k    l    ;    '         ret   pgdn
  lsft z    x    c    v    b    n    m    ,    .    /    rsft      up
  lctl lmet lalt           spc            rctl                left down  rght
)

(deflayer layer-1
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12  del   @num
  grv  1    2    3    4    5    6    7    8    9    0    -    =    del  end
  caps pgup w    pgdn r    t    y    u    i    o    p    home    end    \     pgup
  @lyr1    a    s    d    f    g    left    down   up    right    ;    '         ret   pgdn
  lsft z    x    c    v    b    n    m    ,    .    /    rsft      up
  lctl lmet lalt           spc            rctl                left down  rght
)

(deflayer layer-num
  esc  f1   f2   f3   f4   f5   f6   f7   f8   f9   f10  f11  f12  del   @num
  grv  1    2    3    4    5    6    7    8    9    0    -    =    bspc  end
  tab  7    8    9    r    t    y    u    i    o    p    [    ]    \     pgup
  caps 4    5    6    f    g    h    j    k    l    ;    '         ret   pgdn
  lsft 1    2    3    v    b    n    m    ,    .    /    rsft      up
  lctl lmet 0           spc            rctl                left down  rght
)


;; toggle
(defalias
  num (layer-while-held layer-num)
  lyr1 (layer-while-held layer-1)
)

config에 문법 오류가 없다면 다음의 명령어를 실행했을 때 오류없이 정상 작동해야 한다.

bash
sudo kanata -c $HOME/.config/kanata/rainy75.kbd

혹시나 문법 오류가 존재한다면 kanata가 어느 부분이 틀렸는지 지적해줄 것이다.

sudo 권한 없이 실행 가능하게 만들기

기본적으로 kanata나 kmonad 모두 uinput 모듈에 대한 접근 권한을 필요로 한다. 그래서 sudo가 없이 실행이 안되는 것이다.

kmonad에서는 uinput에 권한을 가진 그룹을 만들고 내 사용자(필자는 will)를 해당 그룹에 포함하는 방식은 실패했었다. 그런데 kanata 공식 가이드 에서도 똑같은 방식을 권하고 있는게 아닌가? 공식 가이드를 따라 다시 시도해봤지만, 여전히 실패한다.

그래서 kmonad에서 한 것처럼 systemd service를 생성해야하나 하다가, 이걸 어떻게든 해결하고 싶었다. 이리저리 구글링하면서 결국 원인을 찾아 해결했다! 해결책은 uinput group을 system 그룹으로 생성하는 것이다.

다음의 명령어를 실행하여 uinput을 시스템 그룹으로 생성하고, $USERinputuinput 그룹에 추가해준다.

bash
sudo groupadd --system uinput
sudo usermod -aG uinput $USER
sudo usermod -aG input $USER

그리고 재부팅 해주자.

재부팅 후, 다음처럼 udev rule을 만들어주자. 여기선 rule 이름을 99-uinput.rules로 지었다. 다음처럼 작성하고 저장해주자.

/etc/udev/rules.d/99-uinput.rules
KERNEL=="uinput", MODE:="0660", GROUP:="uinput", SUBSYSTEM=="misc"

좋다. 다음으로 uinput 모듈이 부팅 시 자동으로 load되도록 해주자.

bash
echo uinput | sudo tee /etc/modules-load.d/uinput.conf

이걸로 되었다. 마지막으로 재부팅하고, 터미널에서 sudo를 빼고 kanata를 실행해보자.

bash
kanata -c $HOME/.config/kanata/rainy75.kbd

정상적으로 작동한다면 성공한 것이다. 이제 남은 것은 부팅 시 자동으로 이 kanata가 실행되도록 만드는 것이다.

자동 실행 설정하기

Autostart 방식은 개인이 사용하는 배포판마다 다르다. Arch 가이드 를 참고하여 각자 배포판에 맞는 방식으로 autostart에 등록해주자.

필자는 사용중인 wm인 dwm의 autostart 항목에 다음처럼 추가해주었다.

.dwm/autostart.sh
#!/bin/sh
kanata -c ".config/kanata/rainy75.kbd"

축하한다. 지금까지 잘 따라왔다면, 재부팅할 때마다 자동으로 kanata가 내가 지정한 키맵핑 파일을 load한 채 데몬으로 동작하게 될 것이다.

Kanata의 강점

이미 설정 과정에 알게 되었을테지만, kanata는 kmonad보다 다음과 같은 몇 가지 측면에서 더 좋다.

뛰어난 documentation

자세한 설치 가이드 제공, 설정 방식에 대한 상세한 설명, 설정 파일 샘플 제공, sudo 권한없이 실행을 위한 방식 제공 등 documentation 관리가 아주 잘 되어있다. 덕분에 kmonad에서처럼 온갖 유튜브와 구글을 뒤져가며 사용방법을 익히지 않아도 된다.

설정파일 오류 검출 기능과 online simulator

kmonad는 config에 오류가 있으면 그냥 실행이 안된다. 어디가 틀렸는지 친절하게 알려주는 법이 없다. 그러나, 우리의 친절한 kanata는 두 가지 방식으로 오류를 진단할 수 있게 해준다.

먼저, 틀린 config을 실행하려하면 정확하게 어디가 틀렸는지를 정확히 지적해준다. (kanata의 개발자는, 아마도, rust의 친절한 디버깅 전략을 수용한 것 같다.)

will@nuclearLab:~/.config/kanata (main)$ kanata -c ~/.config/kanata/rainy75_.kbd 
19:21:41.4345 [INFO] kanata v1.10.0-prerelease-3 starting
19:21:41.4354 [ERROR]   × Error in configuration
   ╭─[/home/will/.config/kanata/rainy75_.kbd:2:1]
 2 │     linux-dev /dev/input/by-id/usb-RDR_Rainy_75-event-kbd
 3 │     process-unmapped-key yes
   ·     ──────────┬─────────
   ·               ╰── Error here
 4 │     log-layer-change no
   ╰────
  help: Unknown defcfg option process-unmapped-key
        
        For more info, see the configuration guide:
        https://github.com/jtroo/kanata/blob/main/docs/config.adoc

19:21:41.4357 [ERROR] failed to parse file


Press enter to exit

한술 더 떠서 kanata의 개발자는 오류를 진단하는 웹페이지(online simulator) 를 운영하고 있다.

kanata의 online simulator
kanata의 online simulator

여기에 config 파일을 통째로 붙여넣으면 어디가 틀렸나 지적해준다. 또한, 변경한 키 스트로크를 테스트 해볼 수도 있다.

모든 OS에서 사용 가능!

개인적으로 언급하고 싶지 않은 부분이지만, kanata는 windows, macOS에서도 동작한다.

혹시 회사의 업무로 인해 windows를 강요당하는 사람이라면!! 리눅스의 쾌적한 키보드 맵핑정도는 윈도우에서도 누릴 수 있다는 의미이다. (물론, 그럼에도 필자는 가상화로 windows를 쓰는 방식을 택할 것이다.)

마무리하며

오늘은 kanata를 통해 키보드 맵핑을 하는 방법을 다뤘다. 이를 통해 QMK/VIA를 지원하지 않는 키보드라 하더라도, 우리는 그와 동일한 기능을 가질 수 있게 되었다.

이번 포스팅에서 자세하게 다루지 않았지만, 단순 toggle-layering 뿐만 아니라 매크로 기능과 cmd 실행 기능 등 많은 고급기능들이 있으니 한번 사용해보길 추천한다. 필자 또한 이런 세부 기능들을 익힌 후 추가로 kanata 포스팅을 이어나갈 계획이다. 특히, 슈퍼파워라고 했던 cmd 기능에 대해서 말이다.

Last updated on