2026年1月19日

keyd を FreeBSD で使いたい (1) 【初手からトラブル編】

Linux 向けのキーリマッピングツール keyd を FreeBSD で使いたい!という試みの顛末を、3 回に分けて書きたいと思います。結論からいいますと、FreeBSD でも使えることは使えたのですが、運用上ちょっと泥臭い感じな細工が必要でした。手っ取り早く結果だけ知りたい方は、【(一応) 完結編】まで読み飛ばしてください。

関連記事:

keyd とは

Linux 向けに書かれたキーリマッピングツールです。次の例のように、Windows 界隈ではおなじみの INI 形式をゆるく取り入れた設定ファイルにより、直感的に設定することができます。

keyd の設定例
[ids]
*

[main]
capslock = layer(control)

なにをやっているかだいたい想像がつくんじゃないでしょうか? [ids] とか layer() とかはぱっと見ではわからないかもしれませんが、次のサイトの解説はわかりやすかったです。

で、これは便利そうだということで、FreeBSD での対応状況を確認したら、ports/packages にはなっていたんですが、メンテナンスが放棄されているようす… (というのがひと月ほど前 (2025 年 12 月頃) のことだったんですが、つい最近 (2026 年 1 月) 新たにメンテナーの方が就任されて、状況が好転したようです)。

keyd が無応答になった場合の対処法

これ以降、いろいろ試すうちに設定をミスって keyd が無応答になってしまうかもしれません。そういうときのために、keyd にはパニックシーケンスが用意されています。具体的には「Esc+BS+Enter」の同時押しです。一見無応答に見えても、実は keyd のイベントループは生きていて、このシーケンスを入力することでループから脱出することができます。

使ってみる…からの初手トラブル

なにはともあれ、せっかく packages になっているのでインストールしてみました。

# pkg install -y keyd

OS 起動時に keyd も起動するように、sysrc コマンドを使って /etc/rc.conf に追記します。

# sysrc keyd_enable="YES"

設定ファイルを用意します。/usr/local/etc/keyd/default.conf を新規作成し、中身は前出の設定例のように書いておきます。

で、OS を再起動し、ログインプロンプトが表示されたら、ユーザー名とパスワードを入力しま…

なんだい、ウンともスンともいわないではないか??? (パニックシーケンスを入力して抜けましょう)

そしてデバッグへ…ソースコードからのビルドとインストール

でも何とかして FreeBSD でも使いたいなあと思ったので、ソースコードから地道にデバッグしてみることにしました。詳細は長くなりすぎるので割愛しますが、ソースコードからのビルドとデバッグ方法だけはここに書き留めておきたいと思います。

なお、もしすでに ports/packages から keyd をインストールしてあるのであれば、無用のトラブルを避けるためにアンインストールしておいたほうがよいと思います。

ソースコードの取得

まず最新リリース版である Ver. 2.6.0 のソースコードを公式リポジトリから取得します。

% git clone https://github.com/rvaiya/keyd.git -b v2.6.0
% cd keyd

ソースコードの修正

keyd は基本的に Linux 向けに書かれているので、FreeBSD で使うには少し修正が必要です。

まず src/daemon.c。run_daemon() の中ほどに「sp.sched_priority = 49;」という行があります。プロセスのスケジューリングの優先度?を設定しているみたいですが、優先度の数値の定義が Linux と FreeBSD では大きく異なるために、FreeBSD ではここのところでエラーになってしまいます (具体的にどんなエラーだったかは忘れましたが、優先度が Out of range だよというようなエラーだったと思います)。

ここは keyd の ports のパッチ (/usr/ports/sysutils/keyd/files/patch-src_daemon.c) を参考にしながら、次のように修正します。

src/daemon.c (差分)
     }

     sp.sched_priority = 49;
+#ifdef __FreeBSD
+    sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
+#endif
     if (sched_setscheduler(0, SCHED_FIFO, &sp)) {
         perror("sched_setscheduler");
         exit(-1);

あとは Makefile です。次の 2 点を変更します。

  • 設定ファイルの置き場所を /usr/local/etc/keyd に変更
  • groupaddgroupdel コマンドの代わりに pw groupaddpw groupdel コマンドを使うように変更
Makefile (差分)
 VKBD=uinput
 PREFIX?=/usr/local

-CONFIG_DIR?=/etc/keyd
+platform=$(shell uname -s)
+
+ifeq ($(platform), FreeBSD)
+    CONFIG_DIR?=/usr/local/etc/keyd
+    GADD=pw groupadd
+    GDEL=pw groupdel
+else
+    CONFIG_DIR?=/etc/keyd
+    GADD=groupadd
+    GDEL=groupdel
+endif
+
 SOCKET_PATH=/var/run/keyd.socket

 CFLAGS:=-DVERSION=\"v$(VERSION)\ \($(COMMIT)\)\" \
@@ -23,7 +34,6 @@
     -Werror=format-security \
     $(CFLAGS)

-platform=$(shell uname -s)

 ifeq ($(platform), Linux)
     COMPAT_FILES=
@@ -73,7 +83,7 @@
     mkdir -p $(DESTDIR)$(PREFIX)/share/doc/keyd/
     mkdir -p $(DESTDIR)$(PREFIX)/share/doc/keyd/examples/

-    -groupadd keyd
+    -$(GADD) keyd
     install -m755 bin/* $(DESTDIR)$(PREFIX)/bin/
     install -m644 docs/*.md $(DESTDIR)$(PREFIX)/share/doc/keyd/
     install -m644 examples/* $(DESTDIR)$(PREFIX)/share/doc/keyd/examples/
@@ -84,7 +94,7 @@
     install -m644 README.md $(DESTDIR)$(PREFIX)/share/doc/keyd

 uninstall:
-    -groupdel keyd
+    -$(GDEL) keyd
     rm -rf $(DESTDIR)$(PREFIX)/bin/keyd \
         $(DESTDIR)$(PREFIX)/bin/keyd-application-mapper \
         $(DESTDIR)$(PREFIX)/share/doc/keyd/ \

ビルドとインストール

あとは普通に gmake して gmake insntall します。ビルド時にいくつか警告が出ますが、この際無視します。

% gmake
# gmake install

ちなみに gmake uninstall でアンインストールすることができます。

OS 起動時に keyd も起動させる

packages でインストールしたときと同様に、sysrc コマンドを使って /etc/rc.conf に追記します。

# sysrc keyd_enable="YES"

それから、rc.d スクリプト (/usr/local/etc/rc.d/keyd) を作ります。/usr/ports/sysutils/keyd/files/keyd.in がほぼそのまま使えます。keyd.in の「procname="%%PREFIX%%/bin/${name}"」というところだけ「procname="/usr/local/bin/${name}"」に変更します (22 行目)。

/usr/local/etc/rc.d/keyd
#!/bin/sh

# PROVIDE: keyd
# REQUIRE: DAEMON
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf to enable this service:
#
# keyd_enable (bool):   Set it to YES to run keyd on startup.
#           Default: NO

. /etc/rc.subr

name="keyd"
rcvar="${name}_enable"

load_rc_config "$name"

: ${keyd_enable="NO"}

command="/usr/sbin/daemon"
procname="/usr/local/bin/${name}"
pidfile="/var/run/${name}.pid"
command_args="-s err -T ${name} -p ${pidfile} ${procname}"

run_rc_command "$1"

パーミッションを変更して、実行できるようにします。

# chmod +x /usr/local/etc/rc.d/keyd

デバッグ方法

keyd はデフォルトである程度デバッグ情報を出力するようになっています。環境変数 KEYD_DEBUG の値でデバッグ情報の詳細度を変更できます。0 ~ 2 の値をとり、大きくなるほど詳細になります。デフォルトは 0 です。デバッグレベル 2 になると、入力したキーのコードからその Up/Down まで全部ログに残ってしまうので、要注意です。

KEYD_DEBUG の値を変更する場合は、前出の /usr/local/etc/rc.d/keyd に書くのがよいと思います。適当な位置 (正直、このスクリプトの書きかたをよく知らないんですが、最終行の「<code.run_rc_command "$1"」よりは前がいいんじゃないかと思います) に次の 1 行を追加してください。

/usr/local/etc/rc.d/keyd (追記)
export KEYD_DEBUG="2"

デバッグ情報は /var/log/messages に出力されますが、任意のファイルに出力することもできます。その場合は、同じスクリプトの 24 行目を次のように変更してください。この行は daemon(8) に渡す引数を定義しています。ここに -o オプションを追加して出力先のファイル名を指定します。

/usr/local/etc/rc.d/keyd (差分)
-command_args="-s err -T ${name} -p ${pidfile} ${procname}"
+command_args="-s err -T ${name} -p ${pidfile} -o /var/log/keyd.log ${procname}"

もし自分でデバッグ情報を出力したい場合は keyd_log() を使います。例えば keyd の起動時に読み込まれるコンフィグレーションファイル名を出力したければ、daemon.c の load_configs() のところに次のように挿入します。

src/daemon.c (差分)
            continue;

        len = snprintf(path, sizeof path, "%s/%s", CONFIG_DIR, dirent->d_name);
+       keyd_log("%s\n", path);

        if (len >= 5 && !strcmp(path + len - 5, ".conf")) {
            struct config_ent *ent = calloc(1, sizeof(struct config_ent));

FreeBSD で使う場合の問題点

で、なんやかやあって最終的にわかったのは、コンソール環境だとダンマリだけど、X11/Wayland 環境なら問題なさそうということです。keyd は evdev(4) というドライバを使って仮想キーボードを作るんですが、FreeBSD のコンソールはこれを見に行くような作りになっていないらしく (ソースは ChatGPT ですが、evdev(4) のマニュアルには「evdev is Xorginput driver for Linux's generic event devices.」と書かれているので、まあそうなんだろうなと思いました)、仮想キーボードから入力したコードがすべて破棄されてしまうようです。一方、Linux の場合はコンソールと X11/Wayland の入力系統が統合されているらしく、このような問題は発生しません。

じゃあ X11/Wayland が起動したときに keyd もいっしょに起動するようにしたらどうだろう?ということで次回に続きます。