[MagicKeyBattery] Windows向けApple Magic Keyboardバッテリー監視ツール

[MagicKeyBattery] Windows向けApple Magic Keyboardバッテリー監視ツール

はじめに

「MagicKeyBattery」は、Windows環境でApple Magic Keyboardのバッテリー残量をタスクトレイに常駐表示するC#アプリケーションです。

WindowsにはMagic Keyboardのバッテリー残量を確認する標準機能がなく、BIOSレベルで認識されているにもかかわらず残量表示の手段が提供されていません。

このツールはWin32 HID APIを直接叩いてバッテリー情報を取得し、外部アセットを一切使わずにタスクトレイアイコンをメモリ上で動的に描画します。

ソースコードとビルド済みバイナリをGitHubで公開しています。

対応デバイス: Apple Magic Keyboard(テンキー付き / Touch IDモデル)

C# / .NET 10 / Win32 HID API / MIT License

ダウンロード・ソースコード

ビルド方法

.NET 10 SDKがインストールされている環境で、以下のコマンドを実行します。

# ソースから直接実行
dotnet run

# スタンドアロン実行ファイルの生成
dotnet publish -c Release -r win-x64 --self-contained false /p:PublishSingleFile=true

スクリーンショット

タスクトレイ

タスクトレイアイコン
タスクトレイアイコン

設定ダイアログ(日本語・英語)

設定ダイアログ(日本語) 設定ダイアログ()

機能一覧

機能説明
バッテリー残量表示タスクトレイに残量をドット描画で常時表示
ゼロアセット動的アイコン外部.icoファイル不要。16×16pxをメモリ上で毎回描画
低バッテリー通知設定閾値以下でWindowsトースト通知(重複防止付き)
マルチ言語対応OS言語を自動検出。日本語/英語の動的切替
設定ダイアログダークテーマUI。更新間隔・通知閾値をGUIで変更可能
スタートアップ登録レジストリ連携でWindows起動時の自動起動をトグル
超低負荷3分間隔のポーリング。CPU・Bluetooth帯域への影響ほぼゼロ

技術的課題と解決

1. キーボード排他制御の回避 ─ アクセス権0ハック

Windowsはセキュリティおよびキー入力の整合性を保つため、標準キーボードデバイス(Col01系統)をシステム側で排他制御しています。

通常のアプリケーションが GENERIC_READ | GENERIC_WRITE でデバイスハンドルを開こうとすると、Win32Error: 5 (Access Denied) で拒絶されます。

Win32 APIの CreateFile を呼び出す際、第2引数のアクセス権(dwDesiredAccess)に 0(アクセス権なし)を指定してハンドルを取得します。

HIDデバイスの仕様上、アクセス権が0であっても HidD_GetInputReport によるコントロールパケットの送受信は許可されるため、システムの排他制御をすり抜けて通信経路を確保できます。

2. Report IDの特定 ─ 総当たりプロービング

Apple製デバイスは、タイピング用のメインチャンネル(Col01)とは別に、制御信号をやり取りするための拡張チャンネル(Col02)を持っています。

モデルやファームウェアによってバッテリー情報を返却するReport IDが異なるため、事前にIDを特定する必要があります。

0x010xFF(255通り)のすべてのReport IDに対し、バッファサイズを変えながら HidD_GetInputReportHidD_GetFeature を網羅的に叩く総当たりプロービングを実施。検証に使用したテンキー付きモデル(PID: 026c)においては以下の仕様でデータが取得できることを特定しました。

パラメータ
窓口Col02 インターフェース
APIHidD_GetInputReport
Report ID0x90
バッテリー残量格納先返却バッファの3バイト目(index 2)
値域0〜100(パーセント)

3. ゼロアセット動的アイコン生成

アプリケーションの軽量化とポータビリティのため、外部の .ico ファイルを一切同梱していません。C#の Graphics クラスを使用し、メモリ上の16×16ピクセルの Bitmap に直接バッテリーの外枠と残量インジケーターを1ピクセル単位で描画しています。

描画のたびに増えるHICONハンドルによるGDIリソースリークを防ぐため、user32.dllDestroyIcon をP/Invokeし、古いハンドルを厳密に破棄する設計としています。

4. バックグラウンドポーリング最適化

OSスタックがキャッシュしているHIDレポートを取得するため、高頻度なスキャンは不要です。

スキャン間隔を3分(180,000ms)に設定し、CPU・Bluetooth帯域・キーボード側のバッテリーのいずれに対しても負荷をほぼゼロに抑えています。

ステータス更新はバックグラウンドスレッドで完全に処理され、コンテキストメニュー表示中のちらつきが発生しない設計です。


対応デバイス

現在、以下のデバイスで動作確認済みです。

デバイスProduct ID接続方式
Apple Magic Keyboard(テンキー付き)026cBluetooth Classic (HID)

他のMagic Keyboardモデル(Touch IDモデル等)でも Col02 + Report ID 0x90 の組み合わせで動作する可能性がありますが、ファームウェアバージョンやモデルによって異なる場合があります。


バージョン履歴

バージョンリリース日内容
v1.0.02026/06/22初版リリース。基本的なバッテリー監視機能
v1.2.02026/06/22設定ダイアログ追加、マルチ言語対応(日本語/英語)、低バッテリー通知、スタートアップ登録

プロジェクト構成

MagicKeyBattery/
├── Program.cs                 (アプリケーション本体・全ロジック)
├── MagicKeyBattery.csproj     (.NET 10プロジェクト定義)
├── LICENSE                    (MIT License)
└── README.md                  (英語ドキュメント)

全ロジックが Program.cs の1ファイルに収まっているシングルファイル設計。Win32 API(hid.dllkernel32.dlluser32.dllsetupapi.dll)のP/Invoke宣言、HIDデバイス列挙、バッテリー読み取り、動的アイコン生成、タスクトレイ制御、設定ダイアログ、レジストリ操作のすべてが1ファイルに含まれています。


開発の経緯

ゲーム開発(lain-lab.comの5タイトル)がひと段落したタイミングで、Bluetooth環境のアップデートも重なり、以前から不便に感じていたMagic Keyboardのバッテリー問題に取り組みました。

C#でコードを書き、GitHubにリポジトリを作成し、ビルド済みバイナリの公開まで一気に進めました。普段はThree.js/TypeScriptの世界にいるため、Win32 APIの排他制御やHIDプロトコルの世界は新鮮で、0x010xFFの総当たりでReport IDを特定した瞬間が開発中のハイライトでした。