C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

USBゲームパッドを使えるようにしたい

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■87399 / inTopicNo.1)  USBゲームパッドを使えるようにしたい
  
□投稿者/ ままぞん (1回)-(2018/05/17(Thu) 17:28:18)

分類:[.NET 全般] 



Win10 64bit、VB2015で
USBゲームパッドを使った簡単なゲームを作りたいと考えています。

http://nanoappli.com/blog/archives/4772
一般的には、DirectX inputが使われるそうです。

それでDirect X SDKをインストールしようとしたのですが
http://nanoappli.com/blog/archives/4739
このページにあるエラーが発生してインストールが完了しませんでした。
このページによれば、Visual C++ 2010 再頒布可能パッケージをいったん削除すればうまくいくそうなのですが、
プログラムのアンインストールのところを見ても
Visual C++ 2010 再頒布可能パッケージは見当たりませんでした。
2012, 2013, 2015だけがインストールされています。

一体どうればDirect X SDKをインストールすることができますでしょうか?


代替案として、Direct Xを使わずにWin32 APIでもゲームパッドを使うことができるそうです。
joyGetPosEx() 関数を使えば良いということは分かりました。
http://dream-drive.net/archives/2011/09/excel_vba6.html
VBAのものですが、ソースコードも見つかって、
ゲームパッドからの信号を認識できるところまではいきました。

しかしながら、ゲームパッドでボタンが押された時に
アクションを起こすようにするにはどのようにすれば良いですか?





引用返信 編集キー/
■87406 / inTopicNo.2)  Re[1]: USBゲームパッドを使えるようにしたい
□投稿者/ 魔界の仮面弁士 (1674回)-(2018/05/18(Fri) 11:38:18)
No87399 (ままぞん さん) に返信
> 一般的には、DirectX inputが使われるそうです。
Microsoft からは、COM 版の
 dx7vb.dll (DirectX 7 for Visual Basic Type Library)
 dx8vb.dll (DirectX 8 For Visual Basic Type Library)
あるいは、.NET 版の
 Microsoft.DirectX.dll
などがありましたが、現在ではサポートされていません。


DirectInput を VB.NET から扱うためのライブラリとしては
 SlimDX
 SharpDX
などがありますので、nuget からこれらを参照設定に加えてみてください。

https://slimdx.org/docs/html/T_SlimDX_DirectInput_Joystick.htm
https://github.com/sharpdx/SharpDX-Samples/blob/master/Desktop/DirectInput/JoystickApp/Program.cs


> それでDirect X SDKをインストールしようとしたのですが

DirectX SDK は 2010年6月版を最後に更新されていません。
それゆえ、最近の環境へのインストールが考慮されていません。

現在は、DirectX は Windows SDK の一部となりましたので、
レガシーなライブラリやサンプルを利用するといった限定的なシナリオ以外では、
古い DirectX SDK をあえて導入する必要は無いと思います。


[DirectX SDK (2010/06)] DXSDK_Jun10.exe
https://www.microsoft.com/en-us/download/details.aspx?id=6812

https://blogs.msdn.microsoft.com/chuckw/2015/08/05/where-is-the-directx-sdk-2015-edition/
>> As noted on MSDN, the DirectX SDK is deprecated. The June 2010 release is the last release,
>> and "DirectX" is now part of the Windows SDK. There are really only three scenarios
>> where you should continue to use the old DirectX SDK:
>>
>> 1. You have code (or perhaps an older book) that makes use of D3DX9, D3DX10, D3DX11, or XACT Engine.
>> 2. Your application uses use XAudio2 and supports Windows 7 systems.
>> 3. You are targeting Windows XP with the alternate v1x0_xp Platform Toolset.
>>
>> Remember that use of the legacy DirectX SDK is not supported for UWP app or Xbox One development.


http://www.northbrain.org/book/contents.html
>> 以前は Visual Studio とは別に DirectX SDK を入手する必要がありましたが、
>> 現在は Visual Studio をインストールすると DirectX SDK も
>> 自動的にインストールされます。


http://www.charatsoft.com/develop/otogema/page/00environment/index.htm
>> ちなみに DirectX SDK は最近の Visual Studio には一緒に同梱されていますが、
>> 実はヘルパー関数と呼ばれる D3DX ライブラリが含まれていません。
>> このサイトではこの D3DX ライブラリを使用しているため、
>> Visual Studio 付属の DirectX SDK は使わずに
>> 別途 D3DX が含まれた少し古めの DirectX SDK を使用します。


> ゲームパッドからの信号を認識できるところまではいきました。
> しかしながら、ゲームパッドでボタンが押された時に
> アクションを起こすようにするにはどのようにすれば良いですか?

joyGetPos(Ex) API は、「この関数を呼び出したとき」の状態を調べるもので、
joySetCapture API は、「ポーリング(タイマー監視)」で状態を調べるものです。

joySetCapture の場合、Form のウィンドウハンドルを渡すと、WndProc メソッドが
呼び出されますので、引数の m.Msg から
 MM_JOY1BUTTONDOWN (= &H3B5)
 MM_JOY1BUTTONUP (= &H3B7)
 MM_JOY1MOVE (= &H3A0)
 MM_JOY1ZMOVE (= &H3A2)
などを判定します。
https://msdn.microsoft.com/en-us/library/windows/desktop/dd743594.aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/dd743687%28v=vs.85%29.aspx


ただし、ボタン数が多い物については対応できませんので、その場合には、
JOYINFOEX 構造体(6軸+32ボタン+ハットに対応)を捉えられる joyGetPosEx API を
ワーカースレッドから定期的に呼び出して、RaiseEvent ステートメント
(あるいはデリゲートの Invoke)で通知するといった実装で対応してみてください。
# 手元にデバイスが無いのでコード例は省略。

http://iyn.cocolog-nifty.com/iyn_blog/2010/01/vb-usb-joystick.html
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e7163456-b3bb-4ea2-8025-bda8072f5246/
http://ytyaru.hatenablog.com/entry/2016/07/16/235849
引用返信 編集キー/
■87409 / inTopicNo.3)  Re[2]: USBゲームパッドを使えるようにしたい
□投稿者/ ままぞん (2回)-(2018/05/18(Fri) 13:58:39)
ありがとうございます。
それでは、SlimDXを使いたいと思います。
Nugetからインストールして、
http://io-fia.blogspot.jp/2011/03/slimdxdirect2d.html

のページを参考に


Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports SlimDX
Imports SlimDX.Direct2D
Imports SlimDX.Windows
Imports SlimDX.DirectInput

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
             Dim form = New RenderForm("SlimDX - DirectInput Sample")
             Dim factory = New Factory
             Dim target = New WindowRenderTarget(factory, New WindowRenderTargetProperties)
             Dim di = New DirectInput
             Dim keyboard = New Keyboard(di)
             keyboard.SetCooperativeLevel(form.Handle, (CooperativeLevel.Foreground Or CooperativeLevel.Nonexclusive))
             keyboard.Properties.BufferSize = 4
             If keyboard.Acquire.IsSuccess Then
                 For Each state In keyboard.GetBufferedData
                     For Each key In state.PressedKeys
                         form.Text = key.ToString
                     Next
                 Next
             End If
             
             target.BeginDraw
             target.Clear
             target.EndDraw
             'Warning!!! Lambda constructs are not supported
             MessagePump.Run(form, () => {  })
             For Each item In ObjectTable.Objects
                 item.Dispose
             Next
    End Sub

というコードを実行してみました。
しかし、

Dim target = New WindowRenderTarget(factory, New WindowRenderTargetProperties)
のところで以下のエラーが発生してしまいます。

型 'SlimDX.Direct2D.Direct2DException' のハンドルされていない例外が SlimDX.dll で発生しました
追加情報:ERROR_INVALID_WINDOW_HANDLE: n/a (-2147023496)


これはどのように対処すれば良いでしょうか?




引用返信 編集キー/
■87410 / inTopicNo.4)  Re[3]: USBゲームパッドを使えるようにしたい
□投稿者/ Hongliang (642回)-(2018/05/18(Fri) 14:12:50)
> Dim target = New WindowRenderTarget(factory, New WindowRenderTargetProperties)

参照先ページの記述では

> var target = new WindowRenderTarget(factory,new WindowRenderTargetProperties(){
> Handle = form.Handle,
> PixelSize = form.ClientSize
> });

ですよね。
VBだとこうかな。

New 型名略 With {
.Handle = 略,
.PixelSize = 略
}
引用返信 編集キー/
■87411 / inTopicNo.5)  Re[3]: USBゲームパッドを使えるようにしたい
□投稿者/ 魔界の仮面弁士 (1676回)-(2018/05/18(Fri) 14:39:22)
2018/05/18(Fri) 14:46:19 編集(投稿者)

No87409 (ままぞん さん) に返信
> http://io-fia.blogspot.jp/2011/03/slimdxdirect2d.html
> のページを参考に

そのコードをそのまま真似るのであれば、Form1 クラス内の Sub Form1_Load から記述するのではなく、

1) ソリューション エクスプローラーから My Project を開き、[アプリケーション]タブを開く
2) アプリケーション フレームワークを無効にする
3) スタートアップ オブジェクトを Form1 から Sub Main に変更する
4) Form1_Load 内に書いていた処理を Sub Main に移動させる

のようにします。(Applicaion.Run が MessagePump.Run に置き換わるイメージ)

Form1_Load 内から呼び出そうとすると、MessagePump.Run の呼び出し時に
 System.InvalidOperationException
  単一スレッド上で 2 回目のメッセージ ループを開始することは有効な操作ではありません。
  Form.ShowDialog を使用してください。
の例外が発生することになります。


> Dim form = New RenderForm("SlimDX - DirectInput Sample")
> form.Text = key.ToString
間違いではないですが、これだと、form 変数なのか Form クラスなのか分かり難いですね。
VB は「大文字小文字を区別しない」言語なので、別の名前にしておいた方が良いでしょう。


> Dim target = New WindowRenderTarget(factory, New WindowRenderTargetProperties)
元のコードにあわせるなら、
 Dim target = New WindowRenderTarget(factory, New WindowRenderTargetProperties() With {.Handle = form.Handle, .PixelSize = form.ClientSize})
ですね。


> 'Warning!!! Lambda constructs are not supported
> MessagePump.Run(form, () => { })
元のコードに書かれている

  MessagePump.Run(form, () =>
  {
    if(keyboard.Acquire().IsSuccess){
      foreach(var state in keyboard.GetBufferedData()){
        foreach(var key in state.PressedKeys){
          form.Text = key.ToString();
        }
      }
    }
    
    target.BeginDraw();
    target.Clear();
    
    target.EndDraw();
  });

を Visual Basic に訳すと、こうなります。

  MessagePump.Run( _
    form, _
    Sub()
      If keyboard.Acquire.IsSuccess Then
        For Each state In keyboard.GetBufferedData()
          For Each key In state.PressedKeys
            form.Text = key.ToString()
          Next
        Next
      End If
      target.BeginDraw()
      target.Clear()
      target.EndDraw()
    End Sub _
  )
引用返信 編集キー/
■87413 / inTopicNo.6)  Re[4]: USBゲームパッドを使えるようにしたい
□投稿者/ ままぞん (3回)-(2018/05/18(Fri) 16:01:42)
ありがとうございます。

提示してくださった操作を試すと
うまく動作しました。

ゲームパッドの信号を取りたい場合には
どのように修正すれば良いでしょうか?

あと、フォーム上にこうしたコードを書くにはどのようにしたら良いですか?
 
引用返信 編集キー/
■87419 / inTopicNo.7)  Re[5]: USBゲームパッドを使えるようにしたい
□投稿者/ ままぞん (5回)-(2018/05/19(Sat) 22:31:23)
いろいろ試してみたのですが
https://github.com/sharpdx/SharpDX-Samples/blob/master/Desktop/DirectInput/JoystickApp/Program.cs

このページを参考にすることで
ゲームパッドの信号を読み取ることに成功しました。

以下はフォームアプリケーションです。


    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load

        Dim dinput As DirectInput = New DirectInput
        ' Search for device
        For Each device As DeviceInstance In dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly)
            ' Create device
            Try
                Joystick = New Joystick(dinput, device.InstanceGuid)
                Exit For
            Catch ex As DirectInputException

            End Try

        Next
        If (Joystick Is Nothing) Then
            Throw New Exception("No joystick found")
        End If

        For Each deviceObject As DeviceObjectInstance In Joystick.GetObjects
            If ((deviceObject.ObjectType And ObjectDeviceType.Axis) <> 0) Then
                Joystick.GetObjectPropertiesById(CType(deviceObject.ObjectType, Integer)).SetRange(-100, 100)
            End If

        Next

        Joystick.Properties.BufferSize = 128   


        Dim MultiProgram_GamePad As System.Threading.Thread = New Thread(Sub() GamePad_run()) With {.IsBackground = True}

        MultiProgram_GamePad.Start()


    End Sub

    Private Sub GamePad_run()

        Do

            If Joystick.Acquire.IsSuccess Then
                Joystick.Poll()



                For Each state In Joystick.GetBufferedData

                    frm.BeginInvoke(SetTextBox_dgl, frm.TextBox4, Joystick.GetCurrentState().X.ToString)

                Next state

            End If

        Loop


    End Sub


のようにして、マルチスレッドにして、Do無限ループでコントローラーの動作を読み取るようにしています。
しかし、この方法だとCPUの一つのスレッドの使用率が100%になってしまいます。
4コア8スレッドだとCPU使用率が12.5%になってしまいます。

一方で、87409にコードを参考にして、MessagePump.Runを利用して


以下はコンソールアプリケーションです。

    Sub main()

        Dim form = New RenderForm("SlimDX - DirectInput Sample")
        Dim factory = New Factory
        Dim target = New WindowRenderTarget(factory, New WindowRenderTargetProperties() With {.Handle = form.Handle, .PixelSize = form.ClientSize})


        Dim dinput As DirectInput = New DirectInput
        ' Search for device
        For Each device As DeviceInstance In dinput.GetDevices(DeviceClass.GameController, DeviceEnumerationFlags.AttachedOnly)
            ' Create device
            Try
                Joystick = New Joystick(dinput, device.InstanceGuid)
                Exit For
            Catch ex As DirectInputException

            End Try

        Next
        If (Joystick Is Nothing) Then
            Throw New Exception("No joystick found")
        End If

        For Each deviceObject As DeviceObjectInstance In Joystick.GetObjects
            If ((deviceObject.ObjectType And ObjectDeviceType.Axis) <> 0) Then
                Joystick.GetObjectPropertiesById(CType(deviceObject.ObjectType, Integer)).SetRange(-100, 100)
            End If

        Next



        Joystick.Properties.BufferSize = 128


        MessagePump.Run(
form,
Sub()
    If Joystick.Acquire.IsSuccess Then
        Joystick.Poll()
        For Each state In Joystick.GetBufferedData

            form.Text = Joystick.GetCurrentState().X.ToString

        Next
    End If
    target.BeginDraw()
    target.Clear()
    target.EndDraw()
End Sub
)

End Sub

のようにすると、CPU使用率が1%程度までしか上がりません。

MessagePump.RunはSlimDXのコンポーネントであることは分かったのですが
どのようなものなのか分かりませんでした。

MessagePump.Runをフォームアプリケーションでも使いたいのですが、

        MessagePump.Run(
Me,
Sub()
    If Joystick.Acquire.IsSuccess Then
        Joystick.Poll()
        For Each state In Joystick.GetBufferedData

            TextBox6.Text = Joystick.GetCurrentState().X.ToString

        Next
    End If
End Sub
)

というコードをForm1_Loadに入れてみたのですが、


型 'System.InvalidOperationException' のハンドルされていない例外が System.Windows.Forms.dll で発生しました

追加情報:単一スレッド上で 2 回目のメッセージ ループを開始することは有効な操作ではありません。Form.ShowDialog を使用してください。

というエラーが出てしまいます。
一体どのようにすれば良いでしょうか?


引用返信 編集キー/
■87420 / inTopicNo.8)  Re[6]: USBゲームパッドを使えるようにしたい
□投稿者/ Azulean (951回)-(2018/05/20(Sun) 06:57:42)
2018/05/20(Sun) 07:10:58 編集(投稿者)

No87419 (ままぞん さん) に返信
> MessagePump.Runをフォームアプリケーションでも使いたいのですが、

そのままでは使えません。

MessagePump.Run は手慣れている人が名前を見るだけで「メッセージループを回すメソッド」であると気づけるものです。
Windows Forms アプリケーションは Program クラス、あるいは VB.NET でデフォルトで有効となっているアプリケーション フレームワークが Application.Run を呼ぶことでメッセージループを動かしています。
このため、例外メッセージで言われているように、「2つ目のメッセージループを開始」することになり、不正な操作となっています。
(これはすでに No87411 で説明されていたことのはずです)

MessagePump.Run の路線でいきたいなら、魔界の仮面弁士さんが紹介していた内容を再度読み直してください。
魔界の仮面弁士さんの手順で紹介されていたもので、MessagePump.Run に渡す Sub() の中身を変えればよいだけ…とは思います。
TextBox6 が見つからないエラーを解消できない…ということであれば、下記のページを見て学習した方がいいかもしれませね。
http://dobon.net/vb/dotnet/form/accessanotherformdata.html

内容が理解できない、うまくいかないなら諦めて、Timer で定期的に状態をチェックするように作ることが現実路線ではないでしょうか。
引用返信 編集キー/
■87421 / inTopicNo.9)  Re[5]: USBゲームパッドを使えるようにしたい
□投稿者/ Azulean (952回)-(2018/05/20(Sun) 07:16:55)
No87413 (ままぞん さん) に返信
> あと、フォーム上にこうしたコードを書くにはどのようにしたら良いですか?

この部分が見えていないだけならと仮定して、Application.Run の代わりに Sub Main で以下を呼ぶイメージ。
MessagePump.Run(Form1, AddressOf Form1.フォームに作ったSubの名前)

※デリゲートとかラムダとか、そのあたりの概念を学んでおいた方が良さそうです。
http://www.atmarkit.co.jp/fdotnet/rapidmaster/rapidmaster_02/rapidmaster_02.html
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ