夏の自由研究 PEBLWEAR TN1で色々遊んでみた
目次
ちょうど去年(2025年夏)頃にPEBLWEAR TN1を買ったんだけどキーボードでええやーん〜スマホ(Spotify)でええやーんってなってちょっと寝かせてた。
で、これいい感じに左手デバイスにならないかな?っておもって、ノブついてるしプロダクトはかわいいし、ちょっと遊んでみようと思ったわけさ!
TN1専用のmacOSアプリを自作した。だいたい2日間。夏の自由研究。

やったことの全体像
作ったのは「TN1 Controller」というメニューバー常駐のSwiftUIアプリ。時系列で並べるとこうなる。
| # | やったこと | 概要 |
|---|---|---|
| 1 | イベント捕捉 | CGEventTapでTN1のキーを全部捕まえて、システムに渡さない |
| 2 | ノブ=機能リスト巡回 | ノブを回すと登録アプリ/モードを順に巡回して切り替え |
| 3 | ボタン=アプリ連動 | 前面アプリのbundleIDごとにボタン3つの動作を定義 |
| 4 | オーディオモード | ノブ=Mac音量、ノブ押しで「切替⇔音量」トグル |
| 5 | PM6006プラグイン | ←=NETWORK / →=LP でアンプの入力切替 |
| 6 | フローティングパネル | 前面アプリとボタンの割り当てを常時表示 |
| 7 | HUD | 切替・入室・音量を画面上部に1.4秒だけ表示 |
| 8 | プラグイン方式 | 機能追加をJSONファイル宣言式に |
| 9 | textInput | チャット欄に定型テキストを送信 |
| 10 | テンプレート | 26アプリ分のボタン割り当てをプリセット化 |
| 11 | 表示モード3択 | 通常/ミニマル/メニューバー |
実測
TN1はBLE HIDのConsumerデバイスとしてMacに見える。ここが分かれば、あとはMac側の話になる。要するに「Bluetoothの音量リモコン」としてOSに認識されている。だからペアリングした時点で、何もしなくても音量調整とPlay/Pauseは効く。
ノブ押しと中央ボタンが同じコードなので、ソフト側では区別できない。「ノブ押しは特別扱いにして、中央ボタンは別の機能に」というのが原理的に無理だった。
ノブ=機能リストの巡回
ノブの割り当ては「音量」ではなく「機能リストを1つずつ進む/戻る」にした。
リストに並ぶのは2種類。
- 登録したアプリ — 選んだ瞬間に前面アプリが切り替わる
- モード — 選ぶと「そのモードに入室」する(オーディオモードなど)
ノブを回すとリスト上のカーソルが動いて、画面上部にHUDが出る。アプリならその場で切り替わり、モードならそのモードの中に入る。

PM6006の入力切替をボタンに乗せる

オーディオモードの中で、ボタンに Marantz PM6006 の入力切替を割り当てた。
- ← = NETWORK
- → = LP
中身は、以前作った入力切替の自動化の流れを汲むMac常駐デーモン(pm6006-input-auto)の手動コマンドを呼んでいるだけ。SwitchBotのスマートリモコンからIRを飛ばして、アンプのリモコンを押すのと同じことをしている。デスクのノブを2回操作すればアンプの入力が変わる、という状態になった。
パネルとHUD
割り当てを覚えられないので、画面に出すことにした。
フローティングパネルは、前面アプリのアイコンと名前、そしてボタン3つのラベルを常時表示する。ドラッグで好きな位置に動かせる。パネル下部にはモード切替バーを置いて、マウスからも操作できるようにした。音量はドット20個のリング表示。
デザインは漆黒+金の「シック×モダン」で統一した。デスク上のTN1がステンレス削り出しなので、画面側も金属っぽい質感に寄せたかった。
HUDのほうは画面上部中央に1.4秒だけ出る通知で、アプリ切替・モード入室・入力切替・音量調整の4種類で表示される。パネルを見ていなくても、操作したことが分かる。
表示モードは3択にした。
| モード | 挙動 |
|---|---|
| 通常 | アイコン+名前+ボタンラベルをフル表示 |
| ミニマル | 記号のみ。ホバーでラベルが出る |
| メニューバー | パネルを消して、メニューバーアイコンに状態表示+ポップオーバーで操作 |
作業中ずっと出しっぱなしにするなら、ミニマルかメニューバーが実用的だった。でもミニマル作ったのはいいけど、ミニマルにするとラベル消えるから、それならフローティングパネルの存在意義は..?とちょっとなる。

設定画面

トラブルと対策
1. ノブ回転イベントの形状が、環境によって変わる
実装当初、ノブを回すとキーのUP(離した側)だけが届いていた。なのでUPを見て処理するコードを書いた。ここまでは正常に動いていた。
ところがDOWN と UP の両方が届くようになった。結果、ノブを1クリック回すと機能リストが2つ進む「二重処理事故」が発生した。
対策としてイベントの形状をログで実測して、こう統一した。
- DOWNを正として処理する
- UPは、対になるDOWNが来ていなかったときだけ処理する
これで、DOWN+UPが来る環境でも、UPだけの環境でも、1回転が1回の処理になる。BLE HIDのイベントは環境やペアリング状態で形が変わり得る、というのが分かっただけでも収穫だった。
2. ボタン長押しが実機で認識されない
Step 4に書いたやつ。ソフト上は成立していたが実機で動かず不採用。長押しに頼らず、確実に届くイベント(ノブ押し)で代替する設計に変更した。
3. Magic Keyboardのメディアキーまで反応する
CGEventTapでメディアキーを消費していたら、当然だけどキーボードの音量キーまで効かなくなった。TN1のイベントも普通のキーボードのイベントも、EventTapのレベルでは同じ「音量キー」でしかない。
そこで IOHIDManager で TN1(VID 0x1915 / PID 0x0003)の入力を直接監視して、発生元を推定する方式にした。
- 音量キーが来たとき、直近150ms以内にTN1からの入力があったかを見る
- あれば → TN1由来とみなして消費する
- なければ → キーボード由来とみなして素通し(システム本来の音量調整が働く)
150msという閾値は実測で決めた。これでMagic Keyboardの音量キーは普通に使えるまま、TN1だけを乗っ取れる。
まとめ
レイアウトやUIはHTMLでいろいろサンプル調整しながら組んだからあまり迷走しなかったはず。
PM6006の操作に関しては、リモコンをリモコンで操作してるわけで車輪車輪してるとは思う。こういうガジェットを再利用というか、自作macアプリで遊べたりするからAI様々サマーやで。
- Hermes Agent(DeepSeek-V4-Flash-0731) + Claude Code + Codex
使っている主な機器・構成
- ノブコントローラー:PEBLWEAR TN1(BLE HID / VID 0x1915 / PID 0x0003)
- アンプ:Marantz PM6006
- USB-DAC/ヘッドホンアンプ:TOPPING DX5 II
- 入力切替の自動化:SwitchBot スマートリモコン + Home Assistant
- 自作アプリ:TN1 Controller(macOS / SwiftUI / CGEventTap + IOHIDManager)