HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2021
0928
zezenanaゲームパッドのドライバ有効無効を簡潔にしたい8解決


zezenana

リンク

2021/9/28(Tue) 09:07:20|NO.94003

スリープ処理のようにWindows10未使用時にゲームパッドのドライバを無効にし、
ウェイクアップ処理のようにWindows10使用時にドライバ有効にするスクリプトを
制作しているのですが、色々と調査して以下のような処理構成となりました。

(経緯:Windows10のスリープしない問題が2018年からあり、
USBゲームパッドの接続監視が原因なのにMSが未だに対策してくれないので。。)

もう少し簡潔にしたいのですが、以下の項目について他の策があれば教えて頂きたいです。

・バッチファイルやPowerShellを介さない方法
(ドライバ有効無効の処理時にコマンド画面を出なくしたい)

・ゲームパッドドライバのインスタンスIDの取得
(現在はデバイスマネージャで調査して手動で貼り付け。
調べる感じだとAPIもなさそうなのでレジストリの検索と取得が必要?)

ネットで調べた所、 VectorにHSP制作のデバイス有効無効(2013年)がありましたが、
WDKツールの devcon.exe を呼び出すもので、インスタンスIDも調査し手動入力でした。
結構古い exeですが、これを使うのが無難なのでしょうか?


■現在の処理構成:

管理者権限で実行
スリープ時 >> 無効化バッチ >> 無効化PowerShell
ウェイク時 >> 有効化バッチ >> 有効化PowerShell

・スクリプトのスリープ・ウェイク部のみ

;管理者権限の確認 管理者でis_admin=1 itimer=0 wakeup=0 repeat await 200 ;CPU使用率監視 30%以上でwakeup=1 ;MOUSEカーソル移動監視 変化ありでwakeup=1 ;MOUSEボタン監視 ONでwakeup=1 ;MOUSEホイール監視(ウィンドウ外で取得できず調査中) ;KEYBOARD入力監視 ONでwakeup=1 ;GAMEPAD有無監視 有りでgpaOn=1 if(gpaOn){ ;GAMEPADパッド入力監視 変化有りでwakeup=1 ;GAMEPADボタン入力監視 ONでwakeup=1 } if(wakeup):itimer=0:else:itimer++ if(is_admin){ if(gpaOn==0&wakeup):exec "GPadDevEna.bat" if(gpaOn&(itimer>5000)):exec "GPadDevDis.bat" } loop

・ドライバ有効無効のバッチとPowerShell
('HID\xxxx'はUSBゲームパッドのインスタンスID)

[GPadDevEna.bat] PowerShell -ExecutionPolicy RemoteSigned %~dp0\GPadDevEna.ps1 [GPadDevEna.ps1] Get-PnpDevice | ? {$_.InstanceId -eq 'HID\xxxx'} | Enable-PnpDevice -Confirm:$false [GPadDevDis.bat] PowerShell -ExecutionPolicy RemoteSigned %~dp0\GPadDevDis.ps1 [GPadDevDis.ps1] Get-PnpDevice | ? {$_.InstanceId -eq 'HID\xxxx'} | Disable-PnpDevice -Confirm:$false



この記事に返信する


GENKI

リンク

2021/9/28(Tue) 22:35:05|NO.94011

インスタンスID…デバイスのベンダーIDとプロダクトIDなどの情報が入ってるあれでしょうか。
HidD_GetAttributesでベンダーIDとプロダクトIDの情報を取り出すところに行く前にそれらしい文字列が入った変数を見た気がする。
↓これとか参考になったりはしないでしょうか。

SIXAXISの情報を取得するサンプル解説 for HSP
https://mclab.uunyan.com/lab/sixaxis/sxs006.htm

API駆使して接続されたHIDを総当りしています。



zezenana

リンク

2021/9/29(Wed) 21:23:35|NO.94015

GENKIさん情報ありがとうございます。

そうです、ベンダー(VID)とプロダクト(PID)の情報です。
そのサンプルの存在には気がつきませんでした。

SIXAXISのサンプルを手直しして確認した所、HidD_GetAttributesから
VIDとPIDが取得でき、該当のゲームパッドの情報も総当りしたものに
あることがわかりました。

あとはこれらVIDとPIDのもとであるインターフェイス名が取得できれば
リストボックス形式で必要なゲームパッドデバイスを選択できるのですが、

多分このスクリプトの中(kernel32.dll、hid.dll、setupapi.dll、
SetupDiGetDeviceInterfaceDetailとか)に
ヒントがありそうです。引き続き調査してみます。


バッチファイルやPowerShellのコマンドウィンドウを
表示しない・介さないドライバの操作方法もあればいいのですが
こちらも引き続き調べてみます
&情報ありましたらよろしくおねがいします。



zezenana

リンク

2021/9/30(Thu) 20:14:07|NO.94021

引き続き調査した結果、また行き詰まってしまいました。

■バッチファイルやPowerShellを介さない方法ですが、Windows Vista以降には
pnputil.exeというPnPユーティリティが搭載されているということがわかったのですが、
管理者権限での exec "pnputil.exe"を実行するとエラー14が出てしまいます。

テストもしましたがファイルは存在するのでフルパス指定でも実行できない理由が
わからなくて困っています。

コマンドライン上で pnputil.exeを確認

> where pnputil.exe C:\Windows\System32\pnputil.exe

以下を管理者権限で実行すると見つからないと表示されるので
exec命令の問題でもなさそうです。

cmdExec="C:\\Windows\\System32\\pnputil.exe" exist cmdExec if (strsize!=-1) { exec cmdExec,2 } else { mes cmdExec+" が見つからない" }

手動での実行は問題なく出来ました(HID\VID_XXXX はインスタンスID)

>pnputil /enable-device "HID\VID_XXXX" >pnputil /disable-device "HID\VID_XXXX"


■インスタンスIDについては解明したので、IDのデバイスとなる
インターフェース名の取得を調べた所、フレンドリー名の取得というのに行き着きまして
ネット上のサンプルでは、SetupDiGetDeviceRegistryPropertyで取得できるという
ところまではたどり着いたのですが、何故か文字数0で名称が取得できません。
SetupDiEnumDeviceInfoは取得できているのでループ処理は終了します(私の環境では22デバイス)


#uselib "hid.dll" #func global HidD_GetHidGuid "HidD_GetHidGuid" int #uselib "setupapi.dll" #func global SetupDiGetClassDevs "SetupDiGetClassDevsW" int,int,int,int #func global SetupDiDestroyDeviceInfoList "SetupDiDestroyDeviceInfoList" int #func global SetupDiEnumDeviceInfo "SetupDiEnumDeviceInfo" int,int,int #func global SetupDiGetDeviceRegistryProperty "SetupDiGetDeviceRegistryPropertyA" int,int,int,int,int,int,int #define global DIGCF_PRESENT $00000002 #define global DIGCF_DEVICEINTERFACE $00000010 #define global SPDRP_FRIENDLYNAME $0000000C dim hidGuid,4 dim dev_Info HidD_GetHidGuid varptr(hidGuid) SetupDiGetClassDevs varptr(hidGuid),0,0,DIGCF_PRESENT|DIGCF_DEVICEINTERFACE dev_Info=stat if(dev_Info==-1) : dialog "invalid handle" : end index=0 repeat dim devInfDat,7 devInfDat(0)=28 SetupDiEnumDeviceInfo dev_Info,index,varptr(devInfDat) if(stat==0) : break iLen=0 sdim friendName,512 ;フレンドリー名の文字数を取得 SetupDiGetDeviceRegistryProperty dev_Info,varptr(devInfDat),SPDRP_FRIENDLYNAME,0,0,0,varptr(iLen) ;フレンドリー名を取得 SetupDiGetDeviceRegistryProperty dev_Info,varptr(devInfDat),SPDRP_FRIENDLYNAME,0,varptr(friendName),iLen,0 mes strf("(%2d)FriendName[%s](%d)",index,friendName,iLen) await 0 index++ loop SetupDiDestroyDeviceInfoList dev_Info mes "Index="+index stop


どちらもHSPスクリプトに関連する質問から逸れてきた気もしますが
何か情報ありましたらよろしくおねがいします。



TOMATO

リンク

2021/9/30(Thu) 20:25:08|NO.94022

一つ目のみの回答です。

HSPの標準ランタイムは 32bit なのですが、
64bit OS環境では C:\Windows\System32\ 等のフォルダはリダイレクトされるため
正しく読み込むことができません。(勝手に C:\Windows\SysWow64\ を読みに行く)

代わりに Sysnative にすることによって、回避することができます。


cmdExec="C:\\Windows\\Sysnative\\pnputil.exe" exist cmdExec if (strsize!=-1) { exec cmdExec,2 } else { mes cmdExec+" が見つからない" }



zezenana

リンク

2021/9/30(Thu) 23:19:21|NO.94023

TOMATOさん情報ありがとうございます。

まさか 64bit OS環境でそのような仕様があるとは思いませんでした。

パスを System32から Sysnativeに変更したことで
管理者権限実行にてpnputilによるドライバの有効無効が出来ることを確認しました。


あとはSetupDiGetDeviceRegistryPropertyのフレンドリー名未取得の問題なのですが
もしかしてサンプルが古いせいかこの方法でのWindows10での取得は未対応って
ことはあるのでしょうか?

ちなみにデバイスの列挙を pnputilで行うと「HID 準拠ゲーム コントローラー」と
フレンドリー名を取得できてるので仕組み自体は存在するようです。

> pnputil /enum-devices /class HIDClass

引き続きこれらについて何か情報がありましたらよろしくおねがいします。



TOMATO

リンク

2021/10/1(Fri) 18:38:45|NO.94030

> ちなみにデバイスの列挙を pnputilで行うと「HID 準拠ゲーム コントローラー」と
> フレンドリー名を取得できてる

デバイスの説明なのではないでしょうか?


#uselib "hid.dll" #func global HidD_GetHidGuid "HidD_GetHidGuid" int #uselib "setupapi.dll" #func global SetupDiGetClassDevs "SetupDiGetClassDevsW" int,int,int,int #func global SetupDiDestroyDeviceInfoList "SetupDiDestroyDeviceInfoList" int #func global SetupDiEnumDeviceInfo "SetupDiEnumDeviceInfo" int,int,int #func global SetupDiGetDeviceRegistryProperty "SetupDiGetDeviceRegistryPropertyA" int,int,int,int,int,int,int #define global DIGCF_PRESENT $00000002 #define global DIGCF_DEVICEINTERFACE $00000010 #define global SPDRP_DEVICEDESC $00000000 #define global SPDRP_FRIENDLYNAME $0000000C dim hidGuid,4 dim dev_Info HidD_GetHidGuid varptr(hidGuid) SetupDiGetClassDevs varptr(hidGuid),0,0,DIGCF_PRESENT|DIGCF_DEVICEINTERFACE dev_Info=stat if(dev_Info==-1) : dialog "invalid handle" : end index=0 repeat dim devInfDat,7 devInfDat(0)=28 SetupDiEnumDeviceInfo dev_Info,index,varptr(devInfDat) if(stat==0) : break iLen=0 sdim friendName,512 ;デバイスの説明の文字数を取得 SetupDiGetDeviceRegistryProperty dev_Info,varptr(devInfDat),SPDRP_DEVICEDESC,0,0,0,varptr(iLen) ;デバイスの説明を取得 SetupDiGetDeviceRegistryProperty dev_Info,varptr(devInfDat),SPDRP_DEVICEDESC,0,varptr(friendName),iLen,0 mes strf("(%2d)DeviceDescription[%s](%d)",index,friendName,iLen) await 0 index++ loop SetupDiDestroyDeviceInfoList dev_Info mes "Index="+index stop


フレンドリ名は取れない場合が多いそうです。


//フレンドリーネームの取得 //取得できないことが多い
https://www.usefullcode.net/2006/12/post_19.html



GENKI

リンク

2021/10/1(Fri) 23:44:56|NO.94032

デバイスの名前がほしいということなので、私が知ってる範囲で近そうなところとして記述しておきます。(フレンドリー名はわかんないです。)

CreateFile → HidD_GetPreparsedData → HidP_GetCaps でHIDP_CAPS構造体取得して、ここから
HidD_GetManufacturerString :メーカー名
HidD_GetProductString :製品名
が得られます。製品名は例えばDS4をBluetooth接続した場合、「Wireless Controller」という名前で取得されます。
あ、取得した後は HidD_FreePreparsedData でリソース開放。

デバイス名はデバイスが持っていることが(個人的経験上)あまり期待できないので、公開されているVID/PIDとメーカー/製品名のリストから判定するのが確実です。


> SetupDiGetDeviceInterfaceDetail

「デバイスインターフェースの詳細情報を格納する構造体」って名前で期待してしまうけど、中にはデバイスへのパスしか入っていないという紛らわしい名前。
中身を取り出すときは、CreateFileなどを使う。


> SIXAXISのサンプルを手直しして確認した所、

あのサンプルが誰かの参考になる日が来るなんて思いもしなかった。
流石にHSP3でこの方面に手を出すやつ誰もおらんだろと思ってた。一人じゃなかった!



zezenana

リンク

2021/10/2(Sat) 13:39:34|NO.94034

TOMATOさん、GENKIさん、情報ありがとうございます。

情報を元に調査を続けた所、名称の取得について無事解決しました。

結論としては、HIDではフレンドリー名は取得できないものとして
TOMATOさんの修正スクリプトでUSBゲームパットの数のみを特定して、
(すべてが「HID 準拠ゲーム コントローラー」となるため)

GENKIさんからご提案いただいた製品名の取得を利用して区別できるように
することで、ゲームパッドデバイスの有効無効処理が全て簡潔になりました。


■TOMATOさん

>デバイスの説明なのではないでしょうか?

フレンドリー名を取得・・と書いたのは私の勘違いでした。すみません
pnputilの出力結果にも「デバイスの説明」と表示されていました。

>フレンドリ名は取れない場合が多いそうです。

SetupDiGetClassDevs の範囲をすべてのクラス(DIGCF_ALLCLASSES =(4))に
変更したところ、フレンドリー名が取得できることを確認しました・・が、
ほとんどが文字数0でした。そのリンク先で言ってることは正しいようです。

インターフェイスデバイスについては 1つも名称が存在しないようですので、
フレンドリー名の利用は諦めました。

修正いただいたスクリプトのように「デバイスの説明」のみを取得するのが
無難なようです。


■GENKIさん

ご提案いただいたメーカー名・製品名の取得をSIXAXISのサンプルで
確認したところメーカー名の取得(HidD_GetManufacturerString)は
ほとんどが空欄で利用できなかったのですが、

製品名の取得(HidD_GetProductString)はゲームパットの型番などが
取得できました(ワイド文字列)。
この情報を使うことでリスト化できそうです。

> HidD_GetPreparsedData → HidP_GetCaps でHIDP_CAPS構造体取得して
>:
>:
> 取得した後は HidD_FreePreparsedData でリソース開放

この処理は特にしなくてもサンプルの HidD_GetAttributesを
差し替えただけで取得できました。

>あのサンプルが誰かの参考になる日が来るなんて思いもしなかった。
>流石にHSP3でこの方面に手を出すやつ誰もおらんだろと思ってた。一人じゃなかった!

リンク先のスクリプトって、GENKIさんの制作物だったのですね。
HSPでデバイスやドライバ制御してる人は見かけなかったので、助かりました。


-----
質問内容がすべて解決したので引き続き制作を進めてみます。
ご協力ありがとうございました。



ONION software Copyright 1997-2023(c) All rights reserved.