はじめに
このリモートシャッターを前回は、RaspberryPi3 のシャットダウンボタンにしましたが、今回は Windows の Bluetooth 2ボタンキーボードにしてみようと。
色々ネットを探してみたのですが、Windows で使用している記事が無くて結構ハマりました。
※ABShutter3の仕様が変わったらしく、2つのボタンで送信キーの差がなくなったようです。どちらのボタンを押しても同じになってしまいました。 1ボタンとしては使えます。2020/10/26更新
Bluetoothリモートシャッターとは
- そもそもこれは、スマホのシャッター用ボタン
- スマホとBluetooth接続して使う
- iOSボタンとAndroidボタンの2つある
- 使わないと自動的に数分で電源OFFになる
- ボタン電池のRS2032
- HIDキーボードとして認識される
用途
キーボードフックを使って、別のキーにねじ曲げてしまおう!
ハード
- Bluetoothリモートシャッター(AB Shutter3)(ダイソー 324円)
- Windows10 Pro 1909
開発用IDE
ソース
作成したソース:ABShutter3Key(github)
Windowsとペアリング
このリモートシャッターは、Windowsとペアリングすれば HIDキーボードとして認識される。ドライバーなどのインストールは必要ない。
リモートシャッターの電源をOFFにしておく
Windows10 > 設定 > デバイス > Bluetoothとその他のデバイス

+Bluetooth またはその他のデバイスを追加する を押下

Bluetooth を押下。リモートシャッターの電源をONにする。
通信距離が短いので、近くで行う。1m以内。

AB Shutter3 を押下

ペアリング済み:
先程のWindows10 > 設定 > デバイス > Bluetoothとその他のデバイス画面に戻ると以下のようになっているはず。もしくは「接続済み」。
デバイスがWindowsに登録された状態。次回以降は、リモートシャッターの電源を入れるとすぐに接続される。この状態はまだ使用できない。リモートシャッターは数分使用しないと電源がOFFになりPCとはこの状態になる。

接続済み:
ペアリングが完了して、リモートシャッターと通信できる状態にある。この状態でないと使用できない。
もしリモートシャッターの電源がONで「ペアリング済み」状態ならiOSボタンを押してみよう「接続済み」になるはず。もしならなけれは、一度電源をOFF→ONにすればいい。

接続動作確認
「接続済み」の状態で iOS/Androidボタンを押して、デスクトップ画面の左上に下図のようボリューム表示が出てれくればOK。

開発メモ
「能書きはいいから使いたんじゃ」というひとは **使い方**へ
iOS/Androidボタン
- iOSボタンは、キー
VK_VOLUME_UPにマッピングされている。なので先程のボリューム表示される。 - Androidボタンは、キー
VK_ENTERVK_VOLUME_UPにマッピングされている。VOLUME_UPの前にENTERが送信されるので、エディタを開いた状態で押すと、改行とボリューム表示がされる。
今回はこのキーVK_ENTER VK_VOLUME_UPをねじ曲げて、別のボタンにしてしまおうということです。
※新しいモノだと仕様が変わったらしく、AndroidボタンでVK_ENTERキーが送信されなくなっています。2020/10/26更新
RawInput API
キーVK_ENTER VK_VOLUME_UP は、当たり前だが通常使用しているキーボードからも送信さる。なので通常のキーボードとリモートシャッターの判定をしないといけない。判定方法として RawInput API を使用する。RawInput APIを使うと HID デバイスの一覧と入力されたHIDデバイスが取得できる。だがRawInput APIでは入力されたキーの変更は一切できない、参照のみ。
VID
HIDデバイスには、VID(ベンダーID)とPID(プロダクトID)があって、これをRawInput APIで取得できるのでリモートシャッターの判定として使う。以下がリモートシャッターのVIDとPID(デバイスドライバ)。
違うようであれば setting.ini を変更する。
[ABShutter3Key]
VID="_VID&02248a_PID&8266"
システムフックAPI SetWindowsHookEx()
昔からあるWindowsシステムAPIで user32.dll にあります。これを使うと色々なイベントをフックできる。SetWindowsHookExW function(winuser.h)
今回はこの中でも、 WH_KEYBOARD と WH_KEYBOARD_LL を使う。昔は WH_KEYBOARD しかなかったと思う。WH_KEYBOARD_LL は 低レベルキーボードフックと言って WH_KEYBOARD よりも低レベルでフックするよう。どちらもグローバルフック(システム全体にフック)することは可能だが、WH_KEYBOARD_LL は実行ファイルだけでグローバルフックできるのに対し、WH_KEYBOARD は DLL にフックプロシージャを書かないといけない決まりがある。そして両フックともフックプロシージャで 戻り値 を 0 以外にすると残りのフックチェーンにメッセージが渡らなくなり、その入力キーをブロックできるはずなのだが VK_VOLUME_UP が WH_KEYBOARD ではブロックできない・・・。仕方がないので両方使う
低レベルであるWH_KEYBOARD_LLのイベントが先に来る。さきほどの RawInput API を含めると
WH_KEYBOARD_LL → RawInput API → WH_KEYBOARD
(※あくまでも私の環境での実測値。公式ではないので、動かなかった場合はゴメンナサイ。)
-
VK_ENTERは RawInput API で HIDデバイス判定をして、WH_KEYBOARDでその入力がリモートシャッターならブロックする -
VK_VOLUME_UPはWH_KEYBOARD_LLでブロックする
ということは、VK_VOLUME_UP は HIDデバイス判定をしていないので、すべてのHIDデバイスでブロックされてしまうことになる。しかし、どのみち RawInput API で VK_VOLUME_UP は判定できないようだった。VK_VOLUME_UP時のHIDデバイスハンドルがNULLなのだ。
まぁ VK_VOLUME_UP キーなんて普段使わないしブロックされても特に日常で困ることはないのでOKとする。
SendKeys
キーボードフックして、VK_ENTER VK_VOLUME_UP キーをブロックしたタイミングで、代替したいキー(もしくは文字列)を送信する。送信は WindowsAPIのSendInput() を使うのだが、ライブラリとして完成度の高いこちらを使わせて頂いた。
使い方
-
ここから(ABShutter3Key)一式をダウンロードする。
(Code > Download Zip) - ダウンロード>解凍後に、
x64/Releaseフォルダにあるsettings.iniをエディタで開く - ボンタンに割り当てたいキーを iOS="任意のキー"、Andoroid="任意のキー" に記述し保存(※)
-
x64/ReleaseフォルダにあるABShutter3Key.exeを実行する - iOS/Androidボタンを押して任意のキーが出力できたら成功
- 終了する場合は、タスクトレイ(システムトレイ)の
ABShutter3KeyアイコンをクリックしてEXITをクリック - 任意のキーが出力できずに、ボリューム表示されるようならばキーボードフックに失敗してかも。
ABShutter3Keyを再起動する - それでもダメなら、
setting.iniの VIDを確認する - 任意のキーが出力できずに、ボリューム表示もされないようならば 「接続済み:」か再確認する
[ABShutter3Key]
VID="_VID&02248a_PID&8266"
iOS="iOS{ENTER}"
Android="Android{ENTER}"
(※)キーの記述は、一文字だけであれば "A"。その他は
| KEY | CODE | 記述例 |
|---|---|---|
| WIN | @ | @d :デスクトップ表示 |
| SHIFT | + | +2 :"ダブルクォーテーション |
| CTRL | ^ | ^c :コピー |
| ALT | % | %{TAB} :タスク切換え |
なお、こちら(SendKeys in C++) の記述が使用可能。ただし、DELAYは使えない。
画面ロック(WIN+L) は {LOCKWORKSTATION}。
(※) settings.iniを編集したら 再起動が必要
最後に
- 私の持っているリモートシャッターが数年前のモノなので VID などが変わっている可能性大です。
- 2つ持っているのですが、個体差があります。
- チャタリングが凄いです(特にAndroidボタン)、連続して表示されるかもしれません。
- SendKeysのDELAYコマンドが使えないので、そのうち使えるように改良したい。
- チャタリング対応もソフト的にしたい。
もし「動いたよ!」とかあればコメントして頂けると励みになります。
良い IoT ライフを!
SpecialThanks!!
SendKeys-in-C (CodeProject)
Combining Raw Input and keyboard Hook to selectively block input from multiple keyboards (CodeProject)

