MX Keys Mini はファンクションキーとメディアキーが同じキーを共有しており、Fnキーで切り替える方式になっています。コンパクトな反面、ファンクションキーを多用するゲームで毎回Fnキーと同時に押すのは面倒…かといって常にFnロックにすると接続先切り替えが面倒。ということで、ゲームないし特定のアプリケーション起動時にだけFnロックにする方法を調査しました。
Table of Contents
- Logi Options+にはそんな機能ない
- レッツ・リバースエンジニアリング
- AutoHotKeyに組み込む
Logi Options+にはそんな機能ない
まず調べたのは公式アプリ、Logi Options+。しかし一目みて分かる通り、キーボード関連の機能はめちゃくちゃ少ないです。当然アプリに応じてFnロックを切り替える機能はありません。あるのは常時一括で切り替えるスイッチのみ。
そこでClaudeさんと相談してみると、どうやらLogi Options+とキーボードはHID++というプロトコルで通信しているという話を聞きつけました。
レッツ・リバースエンジニアリング
というわけで、Logi Options+で先程のスイッチを切り替えるとき、キーボードにはどんな信号が送られているのかを調査しました。Wiresharkを使って、Logi Boltに送られるusbhid信号をキャプチャーします。送信されているパケットを特定し、送信内容をClaudeに解析してもらったところ、以下のような内容を送受信していることが判明しました。PCからの信号は特に暗号化とかはされていないようです。
Fロック ON: 10 01 0c 1b 00 00 01
Fロック OFF: 10 01 0c 1b 00 01 01
この6バイト目の値がFnロック状態のフラグのようです。これをhidapitesterを使ってドングルから送信します。昔のUnifyingレシーバーが刺さっていたり、hidapitesterが勝手にバイト長をパディングしたりしたせいでなかなかうまく行きませんでしたが、なんとか動作する方法を特定。
hidapitester --vidpid 046d/c548 --usagePage 0xFF00 --usage 0x0001 --open --length 7 --send-output <bytes>
<bytes>の部分は上のフラグを含んだバイト列(0x10のような形式でカンマ区切り)です。
AutoHotKeyに組み込む
次は最前面のアプリに応じて切り替える信号を送る方法ですが、こちらもClaudeが教えてくれたAutoHotKeyというソフトを使います。autofnlock.ahkのようなファイル名のスクリプトを適当な場所に作成し、ダブルクリックすると機能するようになります。以下がコード例ですが、最前面にあるアプリのexe名を1秒毎にポーリングし、切り替え時には右下に小さく通知を表示するようになっています。Gamesの部分はお好みで書き換えてください。HidapitesterPathも実際のパスに書き換えるのを忘れずに。
#Requires AutoHotkey v2.0
#SingleInstance Force
Games := ["GenshinImpact.exe", "StarRail.exe", "NexusAnima.exe", "ZenlessZoneZero.exe", "Endfield.exe"]
HidapitesterPath := "C:\Freeware\hidapitester.exe"
CurrentState := -1 ; -1=未初期化, 0=メディア, 1=Fロック
ShowNotification(text) {
static notifyGui := ""
if (notifyGui)
notifyGui.Destroy()
notifyGui := Gui("+AlwaysOnTop -Caption +ToolWindow +E0x20", "FnLock")
notifyGui.BackColor := "202020"
notifyGui.SetFont("s11 cWhite", "Segoe UI")
notifyGui.Add("Text", "x15 y10 w150 h25 Center", text)
; 画面右下に配置
screenW := A_ScreenWidth
screenH := A_ScreenHeight
notifyGui.Show(Format("x{1} y{2} w210 h45 NoActivate", screenW - 230, screenH - 100))
WinSetTransparent(200, notifyGui)
SetTimer(() => notifyGui.Destroy(), -1500)
}
SetFnLock(fnLock) {
global HidapitesterPath, CurrentState
if (CurrentState = fnLock)
return
payload := fnLock
? "0x10,0x01,0x0c,0x1b,0x00,0x00,0x01" ; Fロック ON
: "0x10,0x01,0x0c,0x1b,0x00,0x01,0x01" ; メディアキー
cmd := Format('"{1}" --vidpid 046d/c548 --usagePage 0xFF00 --usage 0x0001 --open --length 7 --send-output {2}', HidapitesterPath, payload)
RunWait('cmd.exe /c ' cmd, , "Hide")
CurrentState := fnLock
msg := fnLock ? "🔒 Fnロック ON" : "🔓️ Fnロック解除"
ShowNotification(msg)
}
IsGameActive() {
global Games
try {
proc := WinGetProcessName("A")
for game in Games
if (StrLower(proc) = StrLower(game))
return true
}
return false
}
CheckActiveWindow(*) {
SetFnLock(IsGameActive() ? 1 : 0)
}
; 起動時に一度実行 + 1秒おきにポーリング
CheckActiveWindow()
SetTimer(CheckActiveWindow, 1000)
あとは、shell:startupに.ahkファイルへのショートカットを置いておけば、PC起動時に自動的に動くようになります。