Ubuntu で Copilot キーを Ctrl 化する

OS

Copilot キーを evsieve で evdev 層から横取りして Ctrl 化・無効化し、systemd で永続化する手順を紹介します。

目次

はじめに

最近 Copilot キー(AI アシスタントキー)を購入しました。以前使っていた Copilot キー非搭載のキーボードでもキーの割当てを変更していたので、今回も同じ要領で行けるかと思いましたが、少し手こずったので手順をメモします。

この記事のゴールは次の通りです。

  • Copilotキー単押し → 単一の RightCtrl として認識される
  • Ctrl + C / Ctrl + V などのショートカットが全アプリで使える
  • 再起動後も自動で有効になる
  • 失敗しても元に戻せる

この記事では右 Ctrl に割当てる手順を紹介しますが、完全に無効化することもできます。

前提

  • Linux + GNOME 環境であること(X11 で動作確認しています)
  • Copilot キー搭載キーボードを使っていること
    • 例: ELECOM Leggero シリーズ (新モデルは「AIアシスタントキー搭載」を公式に謳っています)

まず自分の環境が前提を満たすか確認します。

前提チェック
# x11 か wayland かを確認します。
echo "$XDG_SESSION_TYPE"

# 2つともパスが出ることを確認してください。出なければ sudo apt install x11-utils xinput です。
which xev xinput

読み替え表

以降の手順では、環境依存の値を変数で表します。最初にあなたの値を調べて、この表を埋めてから読み進めてください。

変数表記 意味 著者の例 あなたの値の調べ方
$KEYREMAP_DIR 作業ディレクトリー ~/Documents/apps/keyremap 任意の空き場所で良いです。手順では ~/Documents/apps/keyremap を使います。
$DEVICE_LINK キーボードのデバイス /dev/input/by-id/usb-ELECOM_ELECOM_Leggero-event-kbd ls -l /dev/input/by-id/ | grep -i kbd で特定します。
$YOUR_USER ユーザー名 taikun id -un で確認します。
$EVSIEVE_DIR evsieve のビルド場所 ~/Documents/apps/evsieve 任意です。$KEYREMAP_DIR と分けると管理しやすいと思います。
デバイスを調べる
id -un
ls -l /dev/input/by-id/ | grep -i kbd
# 例:
# usb-ELECOM_ELECOM_Leggero-event-kbd -> ../event5
# usb-ELECOM_ELECOM_Leggero-if01-event-kbd -> ../event6
# → event-kbd 側 (if01 が付かない方) を使うのが一般的?

なぜ普通の方法ではできないのか

結論だけ知りたい方は 手順1 まで読み飛ばして構いません。

なぜ普通の方法ではできないのか

Copilotキーは1つのキーではない

Copilot キーは単一のスキャンコードを送りません。左 Shift + Win + F23 の 3 キーを同時押しすることがハードウェアレベルで実装される仕様です。ハードウェアレベルでの実装なので、ソフトウェア側での制御は簡単ではありません。

Copilot キーの実態を確認する
xev -event keyboard

Copilot キーを 1 回押すと、以下が 2〜3 ms 間隔でほぼ同時に発火します。

xev の出力例 (だいぶ省略してあります)
keycode 133 (Super_L)  ← Win 部分
keycode 50  (Shift_L)  ← ゴースト (仕様)
keycode 201 (F23 相当)  ← F23 部分。XKB 上は XF86TouchpadOff と表示されることがあるようです。

ゴースト Shift が Ctrl+C を壊す

133 番に Ctrl を割当てても、押すたびに Shift が混ざるため、コピペなどのショートカットが成立しません。ゴーストの Shift は本物の左 Shift と同一 keycode のため、ソフトウェア側では分離できません。よってキーマップの書き換えによる修飾子化は断念する必要があります。

evdev層での横取りが必要

X より下の evdev 層で LeftMeta → LeftShift → F23 の順序(デバイスによっては順番が異なるかも?)を検出して飲み込み、代わりに単一の RightCtrl を合成します。使うのは evsieve です。

github.comGitHub - KarsMulder/evsieve: A utility for mapping events from Linux event devices.A utility for mapping events from Linux event devices. - KarsMulder/evsievehttps://github.com/KarsMulder/evsieve

全体像

処理の流れは次の通りです。

  1. Copilotキー押下: Shift + Win + F23 発火
  2. evsieve: evdev層で横取り
  3. 仮想デバイス kbd-no-copilot: 単一の RightCtrl を合成
  4. アプリ: Ctrl+C などが効く

evsieve が物理デバイスを grab し、仮想デバイス kbd-no-copilot を常駐させます。常駐化は root の systemd サービス 1 つで行い、ログイン後の追加設定は不要です。

手順1: デバイスと環境を確認する

デバイスの特定
ls -l /dev/input/by-id/ | grep -i kbd
# $DEVICE_LINK をメモします。
# 例: /dev/input/by-id/usb-ELECOM_ELECOM_Leggero-event-kbd

複数の event-kbd が出る場合は、if01 が付かない方から試します。確実に特定したい場合は、次のコマンドで実際にキーを押して反応する方を選びます。

デバイス特定 (evtest があれば)
sudo evtest
# 一覧から候補を選び、Copilotキーや通常キーを押して反応を見ます。
# Ctrl+C で抜けます。

作業ディレクトリーを用意します。

作業ディレクトリーの準備
mkdir -p ~/Documents/apps/keyremap
ls -ld ~/Documents/apps/keyremap

手順2: evsieveをビルドする

--hook ... sequential ... send-key 方式は安定版 v1.4.0 に無いため、main ブランチをビルドします。Rust と libevdev が必要です。

ビルド場所の準備 (例)
mkdir -p ~/Documents/apps/evsieve
cd ~/Documents/apps/evsieve
git clone --depth 1 https://github.com/KarsMulder/evsieve.git src
Rustの確認
cargo --version
rustc --version
# 出なければ https://rustup.rs/ から rustup を入れてください。

libevdev の dev ファイルが無ければ、システムに入れず局所的な展開で済ませます (ランタイムの libevdev2 は通常存在します)。

libevdev-dev を展開してビルド
mkdir -p debs sysroot
apt-get download libevdev-dev
mv *.deb debs/
dpkg-deb -x debs/libevdev-dev_*.deb sysroot/
LIBRARY_PATH="$PWD/sysroot/usr/lib/x86_64-linux-gnu" cargo build --release --manifest-path src/Cargo.toml
# → src/target/release/evsieve ができます。

機能確認をします。

hook機能があるか確認
./src/target/release/evsieve --help | grep -E "hook|withhold|delay|sequential|send-key"
# 何も出なければ、古いタグを拾っている可能性があります。git pull して再ビルドしてください。

手順3: ファイルを配置する

$KEYREMAP_DIR (例: ~/Documents/apps/keyremap/) に以下を置きます。

  • keyremap
    • evsieve
    • remap.sh
    • keyremap-evsieve.service
ファイル 内容
evsieve ビルド済みバイナリ (コピー)
remap.sh 手動テスト用
keyremap-evsieve.service systemd unit
バイナリのコピーと権限付け
cp ~/Documents/apps/evsieve/src/target/release/evsieve ~/Documents/apps/keyremap/evsieve
chmod +x ~/Documents/apps/keyremap/evsieve
chmod +x ~/Documents/apps/keyremap/remap.sh

remap.sh

./remap.sh start|stop で使います。

  • start: sudo evsieve ... & で起動 → 仮想デバイス出現待ち。二重 grab 防止のために起動中は start を拒否します。
  • stop: evsieve を停止します。
~/Documents/apps/keyremap/remap.sh
#!/bin/bash
set -eu
DIR="$(cd "$(dirname "$0")" && pwd)"
EVSIEVE="$DIR/evsieve"
# ▼ デバイス名に置き換えます。
DEVICE="/dev/input/by-id/usb-ELECOM_ELECOM_Leggero-event-kbd"

usage() {
  echo "Usage: $0 start|stop" >&2
}

wait_for_output() {
  local i=0
  while ! xinput list --name-only 2>/dev/null | grep -qx "kbd-no-copilot"; do
    i=$((i + 1))
    if [ "$i" -ge 100 ]; then
      echo "timed out waiting for kbd-no-copilot" >&2
      return 1
    fi
    sleep 0.2
  done
}

cmd_start() {
  if pgrep -af "[e]vsieve.*kbd-no-copilot" >/dev/null; then
    echo "evsieve is already running. Refusing double grab." >&2
    exit 1
  fi
  # RightCtrl 化する場合です。Copilot キーを完全に無効化するなら --hook の send-key と --delay オプションを外します。
  sudo "$EVSIEVE" \
    --input "$DEVICE" grab \
    --hook key:leftmeta key:leftshift key:f23 sequential period=0.1 send-key=key:rightctrl \
    --withhold \
    --delay key:rightctrl:0 period=0.3 \
    --output name="kbd-no-copilot" create-link="kbd-no-copilot" &
  wait_for_output
  echo "started. Copilot key should now act as RightCtrl."
}

cmd_stop() {
  sudo pkill -f "[e]vsieve.*kbd-no-copilot" || true
  sleep 0.5
  echo "stopped."
}

case "${1:-}" in
  start) cmd_start ;;
  stop) cmd_stop ;;
  *) usage; exit 2 ;;
esac

--hook の period=0.1 というのは、0.1 秒の間に 3 キー(leftmeta, leftshift, f23)が入力された場合にフックを発動するという意味です。xev などで実際に Copilot キーを押して time を計測し、3 キーが(ほぼ)同時入力される期間を調べてください。0.1 秒もあれば十分だと思います。

--delay の period=0.3 というのは、フックが発動した場合、キーを最低でも 0.3 秒間維持するという意味です。

手順4: 手動でテストする

いきなり自動起動はせず、まず手動で動作確認します。

手動テスト
cd ~/Documents/apps/keyremap
./remap.sh start
# 別ターミナルで:
xinput list | grep -i copilot
# 期待値: kbd-no-copilot が見えるはずです。
キー入力の確認
xev -event keyboard
# Copilot キー単押しで Control_R の KeyPress/KeyRelease が出れば成功です。
# Super_L / Shift_L / F23 が出なくなっていることも確認します。

成功したら、エディターやブラウザーで Ctrl + C / Ctrl + V を試します。

戻すときは次の通りです。

手動テストの終了
./remap.sh stop

手順5: 自動起動を登録する

手動テストが通ったら、再起動しても有効になるよう systemd サービスとして登録します。

~/Documents/apps/keyremap/keyremap-evsieve.service
[Unit]
Description=keyremap: convert Copilot key chord to RightCtrl via evsieve
After=multi-user.target

[Service]
Type=simple
ExecStart=/home/YOUR_USER/Documents/apps/keyremap/evsieve --input /dev/input/by-id/DEVICE grab --hook key:leftmeta key:leftshift key:f23 sequential period=0.1 send-key=key:rightctrl --withhold --delay key:rightctrl:0 period=0.3 --output name=kbd-no-copilot create-link=kbd-no-copilot
Restart=on-failure
RestartSec=2

[Install]
WantedBy=multi-user.target

YOUR_USER と DEVICE の 2 か所を、自身の環境を確認して置き換えてください。ExecStart に ~ や $HOME は使えません。絶対パスで書きます。

サービス登録
# YOUR_USER と DEVICE を置換済みか確認します。
grep -n "ExecStart" ~/Documents/apps/keyremap/keyremap-evsieve.service

sudo install -m 644 ~/Documents/apps/keyremap/keyremap-evsieve.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now keyremap-evsieve.service
systemctl is-active keyremap-evsieve.service
# 期待値: active

手順6: 検証する

検証コマンド一式
systemctl is-active keyremap-evsieve.service
# 期待値: active

xinput list | grep -i copilot
# 期待値: kbd-no-copilot が見える

xev -event keyboard
# Copilotキー単押しが Control_R に見えること
# (Super_L / Shift_L / F23 が出ないこと)

その後、Copilotキーを使った Ctrl ショートカット (例: Ctrl + C、Ctrl + Tab) が効くことを確認します。

Copilot キーを無効化だけしたい場合

「Ctrl 化ではなく、誤爆防止で無効化したい」場合は、--hook から send-key=key:rightctrl を外し、末尾の --delay ... も外します。

無効化だけの場合の起動例
sudo ./evsieve \
  --input /dev/input/by-id/DEVICE grab \
  --hook key:leftmeta key:leftshift key:f23 sequential period=0.1 \
  --withhold \
  --output name="kbd-no-copilot" create-link="kbd-no-copilot"

remap.sh と .service の両方を同じ形に揃えてください。片方だけ変えると、手動テストと自動起動で挙動が食い違います。

RightCtrl がアプリで効かないときの代替案

アプリ側が Control_R を受け付けない場合があります。その場合は send-key=key:rightctrl を send-key=key:leftctrl に変えて試してください。それでもダメなら、いったん無効化だけにして、アプリ側の問題か切り分けます。

トラブルシューティング

RightCtrl がアプリで効かない

アプリ側が Control_R を受け付けない場合があります。その場合は Control_L で代用するか、Copilot キーを無効化のみにします (無効化だけしたい場合 参照)。

Copilot キーが何に見えているか確認
xev -event keyboard
# Copilotキー単押しで Control_R が出るか確認します。
# Super_L / Shift_L / F23 が残っていたら hook の period を調整します。

タッチパッドが勝手に切り替わるかも(未検証)

Copilot キーの F23 部分がタッチパッドトグル (XF86TouchpadOff) として解釈される場合があります。この手順では --withhold で3キー同時押しを飲み込んでいるため、通常は起きません。

それでも起きる場合は、--hook の period=0.1 を少し大きめ (例: period=0.2) にして取りこぼしを減らしてください。remap.sh と .service の両方を同じ値に揃えます。

デバイスが見つからない

USB差込口を変えたら by-path が変わります。by-id を使ってください。それでも無い場合は、カーネルが別名で認識していないか確認します。

デバイス再探索
ls -l /dev/input/by-id/ | grep -i kbd
ls -l /dev/input/by-path/ | grep -i kbd
sudo dmesg | tail -30
# キーボードを抜き差しして、どの名前で認識されるか見る

入力不能になった

復旧手順
sudo systemctl stop keyremap-evsieve.service
# または再起動

マウスも効かない場合は、電源ボタン長押しの前に Ctrl + Alt + F3 で TTY に切り替えられるか試します。ダメなら再起動が最速です。再起動すれば grab は解けるため、予備キーボードが無くても復旧できます。ただし自動起動を有効化済みだと再発するため、復旧後はサービスを disable して原因切り分けをしてください。

自動起動の一次無効化 (復旧後)
sudo systemctl disable --now keyremap-evsieve.service

おわりに

  • Copilot キーは 3 キー同時押しなので、キーマップの書き換えだけでは修飾子化できません。
  • evdev 層で evsieve に横取りさせ、単一の RightCtrl を合成します。
  • systemd サービスとして常駐させれば、再起動後も有効になります。

Copilot キーの仕様を知ったときはマイクロソフトやってくれたな…と思いました。今回は Copilot キー搭載のキーボードを買ってしまった人向けの記事になりましたが、そもそも Copilot キー搭載キーボードを買わなければこのような苦労をする必要もありません。

よほどの理由がない限り、Copilot キー搭載キーボードを買うべきではないでしょう。