mcpField
E
emit-fn-key-on-macos

emit-fn-key-on-macos

github.com/terrylica生産性145 回インストール1 日前に更新
リポジトリ

emit-fn-key-on-macos について

macOSでKarabiner-ElementsとDriverKit VirtualHIDDeviceを使い、キーの再マッピングから実際のFnイベントを出すためのスキルです。外部ボタンをFn操作に割り当てる手順、検証方法、前提条件、失敗する方法を説明します。

主な機能

  1. 01Karabiner-ElementsでFnを出力する設定
  2. 02Apple Top Caseキーコードの使用
  3. 03Karabiner-EventViewerでイベントを確認
  4. 04権限とTypeless設定の確認
  5. 05記録済みのFnマッピング失敗を回避

活用シーン

  1. 01外部ボタンをTypelessのプッシュトゥトークに割り当て
  2. 02macOSの音声入力や絵文字ピッカーを起動
  3. 03アプリが反応しないFnマッピングの診断

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/terrylica/cc-skills --skill emit-fn-key-on-macos

インストール後、Claude Code で/emit-fn-key-on-macosを入力して読み込まれたか確認します。

同梱ファイルCLAUDE.mdreferences/failed-approaches.md

詳細

macOS で実際の Fn キーイベントを送信する

自己進化型スキル:このスキルは使用を通じて改善されます。手順に誤りがある、パラメーターが変わった、回避策が必要だった場合は、後回しにせず、すぐにこのファイルを修正してください。実際に再現できる問題がある場合にのみ更新してください。

Macos の Fn キー(最近の MacBook では「グローブ」キーとも呼ばれます)は特殊です。通常の修飾キーではなく、kCGEventFlagMaskSecondaryFn を伴います。このフラグは、ユーザー空間から CGEventPost 経由で設定すると、macOS の入力サブシステムによって破棄されます。多くの「何でもリマップ」ツールは、Fn が Cmd/Option/Ctrl と同じように動作すると想定し、CGEventPost 経由で送信しようとしますが、音声入力、Typeless、macOS の音声入力ショートカット、グローブキー経由の Spotlight、絵文字ピッカーなどでは、何も起きないまま失敗します。

カーネルが受け入れる Fn をユーザー空間から送信する唯一の方法は、DriverKit VirtualHIDDevice です。Karabiner-Elements はこれを搭載しています。そのため、2026 年時点でこの用途に使える FOSS ツールは Karabiner だけです。

このスキルを使う場面

  • ユーザーが、マクロパッドのボタン、マウスボタン、その他の外部キーで次の機能を実行したい場合:
    • Typeless のプッシュ・トゥ・トーク(デフォルトでは pushToTalk: "Fn")
    • macOS の音声入力(Fn Fn のダブルタップ、または「システム設定」での単一 Fn)
    • 絵文字ピッカー(Fn+E)
    • グローブキー経由の Spotlight(Fn)
    • BTT でリマップすると動作しない、アプリ固有の Fn コンボ
  • ユーザーから「BTT ではショートカットが実行されたと表示されるのに、Typeless では何も起きない」と報告があった場合
  • ユーザーが Fn のマッピングに hidutil property --set を試しても効果がない場合
  • ユーザーがキーボードに QMK/ZMK を書き込んだ後、Fn の送信が動作しない場合

前提条件の確認

# 1. Karabiner-Elements installed (the only userland tool that can emit real Fn)?
test -d /Applications/Karabiner-Elements.app && echo OK || brew install --cask karabiner-elements

# 2. Karabiner has Input Monitoring + Accessibility?
#    System Settings → Privacy & Security → Input Monitoring → Karabiner = ON
#    System Settings → Privacy & Security → Accessibility → Karabiner = ON

# 3. On macOS Sequoia+: privileged daemon approved in Login Items?
#    System Settings → General → Login Items → Allow in the Background
#    → Karabiner-Elements Privileged Daemon = ON
#    Without this, Karabiner's DriverKit VirtualHIDDevice won't load and
#    your Fn remap will silently do nothing.

内蔵キーボードで Fn を押すと動作するのに、リマップ経由では動作しない場合は、DriverKit デーモンは読み込まれていますが、リマップルールに誤りがあります。以下の「唯一の魔法の呪文」に進んでください。内蔵キーボードの Fn まで動作しなくなった場合は、前提条件 3 を再確認してください。

重要な事実

┌───────────────────────────┐          ┌───────────────────────────┐
│  Real Fn (from keyboard)  │          │  Fn via CGEventPost(...)  │
│  Hardware → DriverKit →   │          │  Userland app → Quartz →  │
│  HIDEvent with            │          │  kCGEventFlagMaskSecon-   │
│  NX_DEVICE_CAPABILITY_    │          │  daryFn flag is DROPPED   │
│  INPUTKEYBOARD_FUNCTION   │          │  before reaching input    │
│  flag set                 │          │  subsystem.               │
│                           │          │                           │
│  ✅ Typeless / dictation  │          │  ❌ Typeless / dictation  │
│     accept it.            │          │     never fire.           │
└───────────────────────────┘          └───────────────────────────┘

Karabiner-Elements は DriverKit VirtualHIDDevice を登録します。リマップルールで「Fn を送信」と指定すると、ハードウェアキーボードと同じカーネル経路を通じて送信します。NX_DEVICE_CAPABILITY_INPUTKEYBOARD_FUNCTION フラグはそのまま保持されるため、Typeless/音声入力で受け付けられます。

唯一の魔法の呪文

Karabiner の manipulator の to ブロックには、次のように記述します。

{ "apple_vendor_top_case_key_code": "keyboard_fn" }

次のようには記述しません。

  • ❌ {"key_code": "fn"} — そのような key_code は存在せず、何も起きないまま無視されます
  • ❌ {"modifiers": ["fn"]} — キーを押すイベントを伴わない修飾フラグなので、Fn の動作は発生しません
  • ❌ {"consumer_key_code": "..."} — HID 使用ページが異なります
  • ❌ {"key_code": "function"} — Karabiner のキーワードではありません

apple_vendor_top_case_key_code 名前空間は、HID Usage Page 0x00FF(Apple Top Case)の Usage 0x03(Keyboard Fn)に対する Karabiner のマッピングです。これは Apple 純正の内蔵キーボードが使う記述子です。

最小限の動作例

Caps Lock キー(特定の外付けキーボードのみを対象にします。VID/PID を調整してください)を、実際の Fn を送信するようにリマップします。

{
  "description": "Caps Lock → Fn (on external keyboard)",
  "manipulators": [
    {
      "type": "basic",
      "from": { "key_code": "caps_lock" },
      "to": [{ "apple_vendor_top_case_key_code": "keyboard_fn" }],
      "conditions": [
        {
          "type": "device_if",
          "identifiers": [{ "vendor_id": 19530, "product_id": 16725 }]
        }
      ]
    }
  ]
}

~/.config/karabiner/karabiner.json の profile 0 → complex_modifications.rules に追加します。

動作確認

# Open Karabiner-EventViewer
open -a "Karabiner-EventViewer"

# Press your remapped key; the Main tab should show:
# name:  fn (not apple_vendor_top_case_key_code)
# ↑ Karabiner normalizes the display back to "fn" but under the hood it's emitting
#   the Apple-Top-Case variant that carries the kernel flag.

# Then test the real consumer (e.g., Typeless with pushToTalk: "Fn"):
#   Press and hold → mic opens
#   Release → mic closes, transcript appears

EventViewer に正しいイベントが表示されるのに Typeless が反応しない場合:

  1. Typeless にアクセシビリティ権限があることを確認してください
  2. Typeless の app-settings.json で pushToTalk が "Fn" に設定されていることを確認してください("fn" でも "Function" でもありません)
  3. Fn を別のツールが取得していないことを確認してください。Fn をトリガーに設定した BTT があると、Typeless がイベントを受け取る前に横取りします

タップと長押し:Fn を押しっぱなしにする対象として設定しないでください

試したパターン:「上部のボタンをタップ → Return、長押し → Fn」を、Karabiner の to_if_alone と to_if_held_down で実現する方法です。

これを行うと、システム全体で Fn が動作しなくなります。2026-04-21 に失敗を確認しました。to_if_held_down: [{"apple_vendor_top_case_key_code": "keyboard_fn"}] を含むルールを読み込んだ後、内蔵キーボードで直接押しても、macOS の標準 Fn キーが Fn を生成しなくなりました。完全なロールバックが必要でした。

原因はまだ不明です。Karabiner の長押し状態機械が、実際のハードウェア Fn イベントと競合する形で Fn フラグを保持している可能性があります。Karabiner の上流で修正されるまでは、Fn には別のボタンを使ってください。

BTT が失敗する理由(1 行で)

BTT の「Trigger Key Sequence」と「Send Shortcut」アクションは、CGEventCreateKeyboardEvent と CGEventSetFlags を使って CGEventPost を呼び出します。フラグ kCGEventFlagMaskSecondaryFn は CGEventSetFlags に受け付けられます(エラーは発生しません)が、配信前に入力イベントマネージャーによって破棄されます。Apple はこの制約をこれまで一度も文書化していませんが、macOS 13/14/15 で一貫して確認されています。

hidutil が失敗する理由

hidutil property --set '{"UserKeyMapping":[...]}' は HID レポートレベルで動作し、キーコードを入れ替えることはできますが、Fn フラグ を合成することはできません。このフラグは、押されたキーに基づいてキーボードドライバー(DriverKit または Apple の内部キーボードドライバー)が設定します。HID レポートレベルでは偽装できません。これは永続化されるプロパティではなく、イベントごとに計算されるプロパティだからです。

QMK を使える書き換え可能なボードで動作する理由(Jieli クラスでは動作しない理由)

Usage Page 0x00FF、Usage 0x03 を通知する実際の USB HID レポートディスクリプターで NKRO + Apple Fn keycode を設定した QMK ボードは、Fn をネイティブに送信できます。これは 実際の ハードウェアレポートであるため、カーネルに受け付けられます。

しかし、安価な Jieli/Realtek/CH57x パッドは書き換えできません。ファームウェアが焼き付けられており、固定の HID ディスクリプター(通常は標準キーボードの Usage Page 0x07)を公開します。ブートローダーが新しいファームウェアを受け付けないため、QMK/VIA/Vial で何度書き換えても動作しません。

書き換え可能なボードについては、こちらをご覧ください:https://github.com/qmk/qmk_firmware → APPLE_FN_ENABLE。

詳細な参考資料

関連スキル

  • configure-macro-keyboard — このスキルを 1 つの手順として使う、最初から最後までのセットアップワークフロー(より大きな Karabiner ルール内で、外部マクロパッドのボタンを Fn に割り当てます)
  • diagnose-hid-keycodes — ハードウェアが送信するキーコードがまだ分からない場合は、まずこちらを使用してください。その後でここに戻り、Fn に再マッピングしてください。

実行後の振り返り

このスキルの完了後、タスクを終える前に振り返ってください。

  1. 現在地を確認します。 — 編集前に、この SKILL.md が正規のファイルであることを確認します。
  2. 何が失敗しましたか? — 失敗の原因となった指示を修正します。
  3. 予想以上にうまくいったことは何ですか? — 推奨プラクティスに加えます。
  4. 何が変わりましたか? — 実情がドキュメントと異なる場合は、ベンダー ID、キーコード、または FOSS ツールのバージョンを更新します。
  5. 記録します。 — トリガー、修正、根拠を含む進化ログの項目(または 04-anti-patterns.md の行)を追加します。

先送りしないでください。次回の実行では、あなたが残した状態を引き継ぎます。

コメント