OSDN Git Service

#37961 PCとMIDI機器をつなぐケーブルとして「MIDI2.0-USB」を使用している場合に警告を表示する機能を追加。このケーブルを通すと、PCからのMIDI出力...
[dtxmania/dtxmania.git] / FDK / コード / 02.入力 / CInput管理.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Diagnostics;
5 using System.Runtime.InteropServices;
6 using SharpDX.DirectInput;
7
8 namespace FDK
9 {
10         public class CInput管理 : IDisposable
11         {
12                 // 定数
13
14                 public static int n通常音量 = 110;
15
16
17                 // プロパティ
18
19                 public List<IInputDevice> list入力デバイス 
20                 {
21                         get;
22                         private set;
23                 }
24                 public IInputDevice Keyboard
25                 {
26                         get
27                         {
28                                 if( this._Keyboard != null )
29                                 {
30                                         return this._Keyboard;
31                                 }
32                                 foreach( IInputDevice device in this.list入力デバイス )
33                                 {
34                                         if( device.e入力デバイス種別 == E入力デバイス種別.Keyboard )
35                                         {
36                                                 this._Keyboard = device;
37                                                 return device;
38                                         }
39                                 }
40                                 return null;
41                         }
42                 }
43                 public IInputDevice Mouse
44                 {
45                         get
46                         {
47                                 if( this._Mouse != null )
48                                 {
49                                         return this._Mouse;
50                                 }
51                                 foreach( IInputDevice device in this.list入力デバイス )
52                                 {
53                                         if( device.e入力デバイス種別 == E入力デバイス種別.Mouse )
54                                         {
55                                                 this._Mouse = device;
56                                                 return device;
57                                         }
58                                 }
59                                 return null;
60                         }
61                 }
62
63
64                 // コンストラクタ
65                 public CInput管理( IntPtr hWnd )
66                 {
67                         CInput管理初期化( hWnd, true );
68                 }
69                 public CInput管理( IntPtr hWnd, bool bUseMidiIn )
70                 {
71                         CInput管理初期化( hWnd, bUseMidiIn );
72                 }
73
74                 public void CInput管理初期化( IntPtr hWnd, bool bUseMidiIn )
75                 {
76                         this.directInput = new DirectInput();
77                         // this.timer = new CTimer( CTimer.E種別.MultiMedia );
78
79                         this.list入力デバイス = new List<IInputDevice>( 10 );
80                         #region [ Enumerate keyboard/mouse: exception is masked if keyboard/mouse is not connected ]
81                         CInputKeyboard cinputkeyboard = null;
82                         CInputMouse cinputmouse = null;
83                         try
84                         {
85                                 cinputkeyboard = new CInputKeyboard( hWnd, directInput );
86                                 cinputmouse = new CInputMouse( hWnd, directInput );
87                         }
88                         catch
89                         {
90                         }
91                         if (cinputkeyboard != null)
92                         {
93                                 this.list入力デバイス.Add( cinputkeyboard );
94                         }
95                         if ( cinputmouse != null )
96                         {
97                                 this.list入力デバイス.Add( cinputmouse );
98                         }
99                         #endregion
100                         #region [ Enumerate joypad ]
101                         foreach ( DeviceInstance instance in this.directInput.GetDevices( DeviceClass.GameControl, DeviceEnumerationFlags.AttachedOnly ) )
102                         {
103                                 this.list入力デバイス.Add( new CInputJoystick( hWnd, instance, directInput ) );
104                         }
105                         #endregion
106                         if ( bUseMidiIn )
107                         {
108                                 this.proc = new CWin32.MidiInProc( this.MidiInCallback );
109                                 uint nMidiDevices = CWin32.midiInGetNumDevs();
110                                 Trace.TraceInformation( "MIDI入力デバイス数: {0}", nMidiDevices );
111                                 for ( uint i = 0; i < nMidiDevices; i++ )
112                                 {
113                                         CInputMIDI item = new CInputMIDI( i );
114                                         CWin32.MIDIINCAPS lpMidiInCaps = new CWin32.MIDIINCAPS();
115                                         uint num3 = CWin32.midiInGetDevCaps( i, ref lpMidiInCaps, (uint) Marshal.SizeOf( lpMidiInCaps ) );
116                                         if ( num3 != 0 )
117                                         {
118                                                 Trace.TraceError( "MIDI In: Device{0}: midiInDevCaps(): {1:X2}: ", i, num3 );
119                                         }
120                                         else if ( ( CWin32.midiInOpen( ref item.hMidiIn, i, this.proc, 0, 0x30000 ) == 0 ) && ( item.hMidiIn != 0 ) )
121                                         {
122                                                 CWin32.midiInStart( item.hMidiIn );
123                                                 Trace.TraceInformation( "MIDI In: [{0}] \"{1}\" の入力受付を開始しました。", i, lpMidiInCaps.szPname );
124                                         }
125                                         else
126                                         {
127                                                 Trace.TraceError( "MIDI In: [{0}] \"{1}\" の入力受付の開始に失敗しました。", i, lpMidiInCaps.szPname );
128                                         }
129                                         item.strDeviceName = lpMidiInCaps.szPname;
130                                         this.list入力デバイス.Add(item);
131                                 }
132                         }
133                         else
134                         {
135                                 Trace.TraceInformation( "DTXVモードのため、MIDI入力は使用しません。" );
136                         }
137                 }
138                 
139                 
140                 // メソッド
141
142                 public IInputDevice Joystick( int ID )
143                 {
144                         foreach( IInputDevice device in this.list入力デバイス )
145                         {
146                                 if( ( device.e入力デバイス種別 == E入力デバイス種別.Joystick ) && ( device.ID == ID ) )
147                                 {
148                                         return device;
149                                 }
150                         }
151                         return null;
152                 }
153                 public IInputDevice Joystick( string GUID )
154                 {
155                         foreach( IInputDevice device in this.list入力デバイス )
156                         {
157                                 if( ( device.e入力デバイス種別 == E入力デバイス種別.Joystick ) && device.GUID.Equals( GUID ) )
158                                 {
159                                         return device;
160                                 }
161                         }
162                         return null;
163                 }
164                 public IInputDevice MidiIn( int ID )
165                 {
166                         foreach( IInputDevice device in this.list入力デバイス )
167                         {
168                                 if( ( device.e入力デバイス種別 == E入力デバイス種別.MidiIn ) && ( device.ID == ID ) )
169                                 {
170                                         return device;
171                                 }
172                         }
173                         return null;
174                 }
175                 public void tポーリング( bool bWindowがアクティブ中, bool bバッファ入力を使用する )
176                 {
177                         lock( this.objMidiIn排他用 )
178                         {
179 //                              foreach( IInputDevice device in this.list入力デバイス )
180                                 for (int i = this.list入力デバイス.Count - 1; i >= 0; i--)        // #24016 2011.1.6 yyagi: change not to use "foreach" to avoid InvalidOperation exception by Remove().
181                                 {
182                                         IInputDevice device = this.list入力デバイス[i];
183                                         try
184                                         {
185                                                 device.tポーリング(bWindowがアクティブ中, bバッファ入力を使用する);
186                                         }
187                                         catch (SharpDX.SharpDXException e)                                                                              // #24016 2011.1.6 yyagi: catch exception for unplugging USB joystick, and remove the device object from the polling items.
188                                         {
189                                                 if( e.ResultCode == ResultCode.OtherApplicationHasPriority )
190                                                 {
191                                                         // #xxxxx: 2017.5.9: from: このエラーの時は、何もしない。
192                                                 }
193                                                 else
194                                                 {
195                                                         // #xxxxx: 2017.5.9: from: その他のエラーの場合は、デバイスが外されたと想定してRemoveする。
196                                                         this.list入力デバイス.Remove( device );
197                                                         device.Dispose();
198                                                         Trace.TraceError( "tポーリング時に対象deviceが抜かれており例外発生。同deviceをポーリング対象からRemoveしました。" );
199                                                 }
200                                         }
201                                 }
202                         }
203                 }
204
205                 #region [ IDisposable+α ]
206                 //-----------------
207                 public void Dispose()
208                 {
209                         this.Dispose( true );
210                 }
211                 public void Dispose( bool disposeManagedObjects )
212                 {
213                         if( !this.bDisposed済み )
214                         {
215                                 if( disposeManagedObjects )
216                                 {
217                                         foreach( IInputDevice device in this.list入力デバイス )
218                                         {
219                                                 CInputMIDI tmidi = device as CInputMIDI;
220                                                 if( tmidi != null )
221                                                 {
222                                                         CWin32.midiInStop( tmidi.hMidiIn );
223                                                         CWin32.midiInReset( tmidi.hMidiIn );
224                                                         CWin32.midiInClose( tmidi.hMidiIn );
225                                                         Trace.TraceInformation( "MIDI In: [{0}] を停止しました。", new object[] { tmidi.ID } );
226                                                 }
227                                         }
228                                         foreach( IInputDevice device2 in this.list入力デバイス )
229                                         {
230                                                 device2.Dispose();
231                                         }
232                                         lock( this.objMidiIn排他用 )
233                                         {
234                                                 this.list入力デバイス.Clear();
235                                         }
236
237                                         this.directInput.Dispose();
238
239                                         //if( this.timer != null )
240                                         //{
241                                         //    this.timer.Dispose();
242                                         //    this.timer = null;
243                                         //}
244                                 }
245                                 this.bDisposed済み = true;
246                         }
247                 }
248                 ~CInput管理()
249                 {
250                         this.Dispose( false );
251                         GC.KeepAlive( this );
252                 }
253                 //-----------------
254                 #endregion
255
256
257                 // その他
258
259                 #region [ private ]
260                 //-----------------
261                 private DirectInput directInput;
262                 private IInputDevice _Keyboard;
263                 private IInputDevice _Mouse;
264                 private bool bDisposed済み;
265                 private List<uint> listHMIDIIN = new List<uint>( 8 );
266                 private object objMidiIn排他用 = new object();
267                 private CWin32.MidiInProc proc;
268 //              private CTimer timer;
269
270                 private void MidiInCallback( uint hMidiIn, uint wMsg, int dwInstance, int dwParam1, int dwParam2 )
271                 {
272                         int p = dwParam1 & 0xF0;
273                         if( wMsg != CWin32.MIM_DATA || ( p != 0x80 && p != 0x90 && p != 0xB0 ) )
274                                 return;
275
276             long time = CSound管理.rc演奏用タイマ.nシステム時刻;  // lock前に取得。演奏用タイマと同じタイマを使うことで、BGMと譜面、入力ずれを防ぐ。
277
278                         lock( this.objMidiIn排他用 )
279                         {
280                                 if( ( this.list入力デバイス != null ) && ( this.list入力デバイス.Count != 0 ) )
281                                 {
282                                         foreach( IInputDevice device in this.list入力デバイス )
283                                         {
284                                                 CInputMIDI tmidi = device as CInputMIDI;
285                                                 if( ( tmidi != null ) && ( tmidi.hMidiIn == hMidiIn ) )
286                                                 {
287                                                         tmidi.tメッセージからMIDI信号のみ受信( wMsg, dwInstance, dwParam1, dwParam2, time );
288                                                         break;
289                                                 }
290                                         }
291                                 }
292                         }
293                 }
294                 //-----------------
295                 #endregion
296         }
297 }