古い購入物を整理していたら、不明なUSB機器出てきた。
AVerMedia Live Gamer HD AVT-C985。
![](https://nehori.com/nikki/wp-content/uploads/cocoon-resources/blog-card-cache/9e364d1272dae0e456edf95ace7d67d9.jpg)
配信に対応したPC内蔵型のキャプチャーボードっぽいけど肝心のキャプチャボードは存在しておらず、録画専用のボタンだけある……。
ゴミじゃん!
と思って処分しようと思ったけれど、ボタンを押してると あのCMが頭をよぎった。
正解は「越後製菓」!
![](http://nehori.com/nikki/wp-content/plugins/a3-lazy-load/assets/images/lazy_placeholder.gif)
これ動かして「越後製菓!」「異議あり!(逆転裁判)」「へぇへぇ(トリビアの泉)」とか言わせてみたいな……
Windowsドライバから実装が必要ならハードルは高いけど、Windows10で一応認識はするみたい。
でググってみると似た内容の記事も見つかった。
![](https://www.autoitscript.com/forum/uploads/monthly_2018_07/Live_Gamer_HD_Button.jpg.9302e0dd0471d9d4704cff30c73161fc.jpg)
「Autoit」を使っているぽいけど、Pythonで簡単に動かせるんじゃない?
未知のUSBデバイスをWindows上でPythonを使って動かしてみる
実際に行った手順を記載しておく。
次の方法で、どんなデバイスでも同じように動かす事ができると思ってる。
Step1)hidapi.dllをダウンロードして動作確認
hidapiの公式リポジトリからWindows用のバイナリをダウンロードする。
![](http://nehori.com/nikki/wp-content/plugins/a3-lazy-load/assets/images/lazy_placeholder.gif)
- 最新のリリース(例:
hidapi-0.14.0
)を選択し、hidapi.dll
を含むZIPファイルをダウンロードする。 - Pythonの実行コードと同じディレクトリに
hidapi.dll
を置く。
その後、Pipで必要なライブラリをインストール。
1 2 |
pip install hid pip install hidapi |
そして実装コード。
System32とかPythonの実行ディレクトリではなくローカルフォルダにDLLを置いているので、DLLのパスを設定後に「import hid」をする必要がある。
途中で importするとコードが汚いので「importlib」を利用してハック的な書き方をしている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
# coding: utf-8 import io import sys import os import importlib # 標準出力と標準エラー出力をUTF-8に設定 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') # スクリプトのディレクトリを取得 script_dir = os.path.dirname(os.path.abspath(__file__)) # DLLのパスを追加 os.add_dll_directory(script_dir) # hidライブラリを動的にインポート hid = importlib.import_module("hid") print("hidライブラリが正しくインポートされました。") |
これで print文が表示されているならPythonの実装環境は整った。
Step2)デバイスを接続してVendor IDとProduct IDを取得
次に未知のUSBデバイスをWindows PCと接続して、接続されているUSB機器の全情報を出力する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# coding: utf-8 import io import sys import os import importlib # 標準出力と標準エラー出力をUTF-8に設定 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') # スクリプトのディレクトリを取得 script_dir = os.path.dirname(os.path.abspath(__file__)) # DLLのパスを追加 os.add_dll_directory(script_dir) # hidライブラリを動的にインポート hid = importlib.import_module("hid") # 接続されているHIDデバイスを列挙 def list_hid_devices(): devices = hid.enumerate() for device in devices: print(f"VendorId: {hex(device['vendor_id'])}, ProductId: {hex(device['product_id'])}, Product: {device['product_string']}") print("接続されているHIDデバイス:") list_hid_devices() |
USB機器を接続した状態で実行すると次のように複数のUSB機器が表示される。
VendorId: 0x45e, ProductId: 0x0, Product:
VendorId: 0x46d, ProductId: 0xc52b, Product: USB Receiver
…..
VendorId: 0x7ca, ProductId: 0x9850, Product:
で「VendorId: 0x7ca, ProductId: 0x9850」機器が「AVerMedia Live Gamer HD AVT-C985」のことを指している。
Step3)ボタン押下を監視して「Hello world」を出力
では今回の「Hello world」。
未知のUSB機器のボタンは一つだけなので、押されたら「Hello world」と返すような実装をしてみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# coding: utf-8 import io import sys import os import importlib # 標準出力と標準エラー出力をUTF-8に設定 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') # スクリプトのディレクトリを取得 script_dir = os.path.dirname(os.path.abspath(__file__)) # DLLのパスを追加 os.add_dll_directory(script_dir) # hidライブラリを動的にインポート hid = importlib.import_module("hid") # ターゲットデバイスのVendor IDとProduct ID TARGET_VENDOR_ID = 0x07CA TARGET_PRODUCT_ID = 0x9850 try: # デバイスを列挙してターゲットデバイスを検索 devices = hid.enumerate() target_device_path = None for device in devices: if device['vendor_id'] == TARGET_VENDOR_ID and device['product_id'] == TARGET_PRODUCT_ID: target_device_path = device['path'] break if not target_device_path: print("ターゲットデバイスが見つかりませんでした。") else: # ターゲットデバイスに接続 device = hid.Device(path=target_device_path) print("ターゲットデバイスに接続しました!") print("ボタンを押してください...") # ボタン押下を監視 while True: data = device.read(64) # デバイスから64バイト読み取る if data: print("ボタンが押されました!") print(f"データ: {data}") # ボタン押下時にHello worldを表示 print("Hello world") break # デバイスを閉じる device.close() print("デバイスを閉じました。") except Exception as e: print(f"エラー: {e}") |
結果は次のようにコンソール上に表示される。
1 2 3 4 5 6 7 |
# # python click.py ターゲットデバイスに接続しました! ボタンを押してください... ボタンが押されました! データ: b'\x01\x01\x00\x00\x00\x00\x00\x00' Hello world デバイスを閉じました。 |
\x01
)】通常、デバイスの状態を示す(例: ボタンが押されたかどうか)。
【2番目のバイト(\x01
)】
押されたボタンのIDを示すことが多い。
例)2番目のバイト**(\x01
, \x02
, \x03
)
【残りのバイト(\x00\x00\x00\x00\x00\x00
)】
他のボタンや追加の情報(例: 軸の位置、圧力センサーの値など)を示す場合がある。
Step4)ffmpegでmp3の無劣化カット
ここまで出来たら、あとは「いかに面白く応用するか?」だけ。
明らかに個人が用意したであろう「越後製菓ーーーーーーー!!!!!.mp3」が見つかったので、ここから必要なデータを抽出する。
![](http://nehori.com/nikki/wp-content/plugins/a3-lazy-load/assets/images/lazy_placeholder.gif)
コマンドはffmpegを使って次のとおり。
1 |
ffmpeg -ss 4.5 -t 2 -i echigo.mp3 -c:a copy output.mp3 |
このファイルをPythonコードと同じディレクトリに入れておく。
Step5)そして完成へ
ボタンを押すと音を出したい。
音声出力は通常はシンプルなplaysoundを利用するが、クリック後のタイムラグを極力減らすために「pygameライブラリ(高速な音声再生が可能)」を利用する。
1 |
pip install pygame |
実装コードは次のとおり。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# coding: utf-8 import io import sys import os import importlib import pygame # 音声再生用ライブラリ # 標準出力と標準エラー出力をUTF-8に設定 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') # スクリプトのディレクトリを取得 script_dir = os.path.dirname(os.path.abspath(__file__)) # DLLのパスを追加 os.add_dll_directory(script_dir) # hidライブラリを動的にインポート hid = importlib.import_module("hid") # ターゲットデバイスのVendor IDとProduct ID TARGET_VENDOR_ID = 0x07CA TARGET_PRODUCT_ID = 0x9850 # Pygameの初期化 pygame.mixer.init() def play_sound(file): """音声ファイルを再生する""" pygame.mixer.music.load(file) pygame.mixer.music.play() try: # デバイスを列挙してターゲットデバイスを検索 devices = hid.enumerate() target_device_path = None for device in devices: if device['vendor_id'] == TARGET_VENDOR_ID and device['product_id'] == TARGET_PRODUCT_ID: target_device_path = device['path'] break if not target_device_path: print("ターゲットデバイスが見つかりませんでした。") else: # ターゲットデバイスに接続 device = hid.Device(path=target_device_path) print("ターゲットデバイスに接続しました!") print("ボタンを押してください...") # ボタン押下を無限ループで監視 while True: data = device.read(64) # デバイスから64バイト読み取る if data: print("ボタンが押されました!") print(f"データ: {data}") # ボタン押下時に音声を再生 play_sound('output.mp3') # デバイスを閉じる device.close() print("デバイスを閉じました。") except Exception as e: print(f"エラー: {e}") |
で、完成。
おわりに
保有知識+ChatGPT-4oを使ったら1時間ぐらいでやりたいことが出来てしまった。
正直ブログを書くほうが面倒だった。
で、一気に勢い&ノリで作ったが、作って周囲に使ってもらうと湧いたのは一瞬で基本は
状態だった。
加えて自身も全く用途が思いつかない。
ただ「USBデバイスを押すとWindows上で認識をする」という基本動作は応用できる技術だと思うのでブログとしてまとめておいた。
実は9年前にも実装した事があったけどね。
![](https://nehori.com/nikki/wp-content/uploads/2016/11/Clipboard02-160x90.jpg)
ちなみにオンラインで遊びたいなら下記に色々なボタンがあるしMP3としてもDL可能(越後製菓以外)。
![](https://nehori.com/nikki/wp-content/uploads/cocoon-resources/blog-card-cache/de752d8f190ac9f20042418d72055953.jpg)
![](https://nehori.com/nikki/wp-content/uploads/cocoon-resources/blog-card-cache/de752d8f190ac9f20042418d72055953.jpg)