00001 #region License
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #endregion
00027
00028 using System;
00029 using System.Collections.Generic;
00030 using System.Text;
00031 using System.Runtime.InteropServices;
00032 using OpenTK.Input;
00033 using System.Security;
00034 using Microsoft.Win32;
00035 using System.Diagnostics;
00036
00037 namespace OpenTK.Platform.Windows
00038 {
00039 sealed class WinMMJoystick : IJoystickDriver
00040 {
00041 #region Fields
00042
00043 List<JoystickDevice> sticks = new List<JoystickDevice>();
00044 IList<JoystickDevice> sticks_readonly;
00045
00046
00047
00048
00049
00050
00051 bool disposed;
00052
00053 #endregion
00054
00055 #region Constructors
00056
00057 public WinMMJoystick()
00058 {
00059 sticks_readonly = sticks.AsReadOnly();
00060
00061
00062 int number = 0;
00063 while (number < UnsafeNativeMethods.joyGetNumDevs())
00064 {
00065 JoystickDevice<WinMMJoyDetails> stick = OpenJoystick(number++);
00066 if (stick != null)
00067 {
00068 sticks.Add(stick);
00069 }
00070 }
00071 }
00072
00073 #endregion
00074
00075 #region Private Members
00076
00077 JoystickDevice<WinMMJoyDetails> OpenJoystick(int number)
00078 {
00079 JoystickDevice<WinMMJoyDetails> stick = null;
00080
00081 JoyCaps caps;
00082 JoystickError result = UnsafeNativeMethods.joyGetDevCaps(number, out caps, JoyCaps.SizeInBytes);
00083 if (result != JoystickError.NoError)
00084 return null;
00085
00086 int num_axes = caps.NumAxes;
00087 if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0)
00088 num_axes += 2;
00089
00090 stick = new JoystickDevice<WinMMJoyDetails>(number, num_axes, caps.NumButtons);
00091 stick.Details = new WinMMJoyDetails(num_axes);
00092
00093
00094 int axis = 0;
00095 if (axis < caps.NumAxes)
00096 { stick.Details.Min[axis] = caps.XMin; stick.Details.Max[axis] = caps.XMax; axis++; }
00097 if (axis < caps.NumAxes)
00098 { stick.Details.Min[axis] = caps.YMax; stick.Details.Max[axis] = caps.YMin; axis++; }
00099 if (axis < caps.NumAxes)
00100 { stick.Details.Min[axis] = caps.ZMax; stick.Details.Max[axis] = caps.ZMin; axis++; }
00101 if (axis < caps.NumAxes)
00102 { stick.Details.Min[axis] = caps.RMin; stick.Details.Max[axis] = caps.RMax; axis++; }
00103 if (axis < caps.NumAxes)
00104 { stick.Details.Min[axis] = caps.UMin; stick.Details.Max[axis] = caps.UMax; axis++; }
00105 if (axis < caps.NumAxes)
00106 { stick.Details.Min[axis] = caps.VMax; stick.Details.Max[axis] = caps.VMin; axis++; }
00107
00108 if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0)
00109 {
00110 stick.Details.PovType = PovType.Exists;
00111 if ((caps.Capabilities & JoystCapsFlags.HasPov4Dir) != 0)
00112 stick.Details.PovType |= PovType.Discrete;
00113 if ((caps.Capabilities & JoystCapsFlags.HasPovContinuous) != 0)
00114 stick.Details.PovType |= PovType.Continuous;
00115 }
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 if (stick != null)
00130 Debug.Print("Found joystick on device number {0}", number);
00131 return stick;
00132 }
00133
00134 #endregion
00135
00136 #region IJoystickDriver
00137
00138 public int DeviceCount
00139 {
00140 get { return sticks.Count; }
00141 }
00142
00143 public IList<JoystickDevice> Joysticks
00144 {
00145 get { return sticks_readonly; }
00146 }
00147
00148 public void Poll()
00149 {
00150 foreach (JoystickDevice<WinMMJoyDetails> js in sticks)
00151 {
00152 JoyInfoEx info = new JoyInfoEx();
00153 info.Size = JoyInfoEx.SizeInBytes;
00154 info.Flags = JoystickFlags.All;
00155 UnsafeNativeMethods.joyGetPosEx(js.Id, ref info);
00156
00157 int num_axes = js.Axis.Count;
00158 if ((js.Details.PovType & PovType.Exists) != 0)
00159 num_axes -= 2;
00160
00161 int axis = 0;
00162 if (axis < num_axes)
00163 { js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.XPos, axis)); axis++; }
00164 if (axis < num_axes)
00165 { js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.YPos, axis)); axis++; }
00166 if (axis < num_axes)
00167 { js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.ZPos, axis)); axis++; }
00168 if (axis < num_axes)
00169 { js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.RPos, axis)); axis++; }
00170 if (axis < num_axes)
00171 { js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.UPos, axis)); axis++; }
00172 if (axis < num_axes)
00173 { js.SetAxis((JoystickAxis)axis, js.Details.CalculateOffset((float)info.VPos, axis)); axis++; }
00174
00175 if ((js.Details.PovType & PovType.Exists) != 0)
00176 {
00177 float x = 0, y = 0;
00178
00179
00180
00181
00182 if ((JoystickPovPosition)info.Pov != JoystickPovPosition.Centered)
00183 {
00184 if (info.Pov > (int)JoystickPovPosition.Left || info.Pov < (int)JoystickPovPosition.Right)
00185 { y = 1; }
00186 if ((info.Pov > (int)JoystickPovPosition.Forward) && (info.Pov < (int)JoystickPovPosition.Backward))
00187 { x = 1; }
00188 if ((info.Pov > (int)JoystickPovPosition.Right) && (info.Pov < (int)JoystickPovPosition.Left))
00189 { y = -1; }
00190 if (info.Pov > (int)JoystickPovPosition.Backward)
00191 { x = -1; }
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 js.SetAxis((JoystickAxis)axis++, x);
00224 js.SetAxis((JoystickAxis)axis++, y);
00225 }
00226
00227 int button = 0;
00228 while (button < js.Button.Count)
00229 {
00230 js.SetButton((JoystickButton)button, (info.Buttons & (1 << button)) != 0);
00231 button++;
00232 }
00233 }
00234 }
00235
00236 #endregion
00237
00238 #region IDisposable
00239
00240 public void Dispose()
00241 {
00242 Dispose(true);
00243 GC.SuppressFinalize(this);
00244 }
00245
00246 void Dispose(bool manual)
00247 {
00248 if (!disposed)
00249 {
00250 if (manual)
00251 {
00252 }
00253
00254 disposed = true;
00255 }
00256 }
00257
00258 ~WinMMJoystick()
00259 {
00260 Dispose(false);
00261 }
00262
00263 #endregion
00264
00265 #region UnsafeNativeMethods
00266
00267 [Flags]
00268 enum JoystickFlags
00269 {
00270 X = 0x1,
00271 Y = 0x2,
00272 Z = 0x4,
00273 R = 0x8,
00274 U = 0x10,
00275 V = 0x20,
00276 Pov = 0x40,
00277 Buttons = 0x80,
00278 All = X | Y | Z | R | U | V | Pov | Buttons
00279 }
00280
00281 enum JoystickError : uint
00282 {
00283 NoError = 0,
00284 InvalidParameters = 165,
00285 NoCanDo = 166,
00286 Unplugged = 167
00287
00288
00289 }
00290
00291 [Flags]
00292 enum JoystCapsFlags
00293 {
00294 HasZ = 0x1,
00295 HasR = 0x2,
00296 HasU = 0x4,
00297 HasV = 0x8,
00298 HasPov = 0x16,
00299 HasPov4Dir = 0x32,
00300 HasPovContinuous = 0x64
00301 }
00302
00303 enum JoystickPovPosition : ushort
00304 {
00305 Centered = 0xFFFF,
00306 Forward = 0,
00307 Right = 9000,
00308 Backward = 18000,
00309 Left = 27000
00310 }
00311 struct JoyCaps
00312 {
00313 public ushort Mid;
00314 public ushort ProductId;
00315 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
00316 public string ProductName;
00317 public int XMin;
00318 public int XMax;
00319 public int YMin;
00320 public int YMax;
00321 public int ZMin;
00322 public int ZMax;
00323 public int NumButtons;
00324 public int PeriodMin;
00325 public int PeriodMax;
00326 public int RMin;
00327 public int RMax;
00328 public int UMin;
00329 public int UMax;
00330 public int VMin;
00331 public int VMax;
00332 public JoystCapsFlags Capabilities;
00333 public int MaxAxes;
00334 public int NumAxes;
00335 public int MaxButtons;
00336 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
00337 public string RegKey;
00338 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
00339 public string OemVxD;
00340
00341 public static readonly int SizeInBytes;
00342
00343 static JoyCaps()
00344 {
00345 SizeInBytes = Marshal.SizeOf(default(JoyCaps));
00346 }
00347 }
00348
00349 struct JoyInfoEx
00350 {
00351 public int Size;
00352 [MarshalAs(UnmanagedType.I4)]
00353 public JoystickFlags Flags;
00354 public int XPos;
00355 public int YPos;
00356 public int ZPos;
00357 public int RPos;
00358 public int UPos;
00359 public int VPos;
00360 public uint Buttons;
00361 public uint ButtonNumber;
00362 public int Pov;
00363 uint Reserved1;
00364 uint Reserved2;
00365
00366 public static readonly int SizeInBytes;
00367
00368 static JoyInfoEx()
00369 {
00370 SizeInBytes = Marshal.SizeOf(default(JoyInfoEx));
00371 }
00372 }
00373
00374 static class UnsafeNativeMethods
00375 {
00376 [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity]
00377 public static extern JoystickError joyGetDevCaps(int uJoyID, out JoyCaps pjc, int cbjc);
00378 [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity]
00379 public static extern uint joyGetPosEx(int uJoyID, ref JoyInfoEx pji);
00380 [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity]
00381 public static extern int joyGetNumDevs();
00382 }
00383
00384 #endregion
00385
00386 #region enum PovType
00387
00388 [Flags]
00389 enum PovType
00390 {
00391 None = 0x0,
00392 Exists = 0x1,
00393 Discrete = 0x2,
00394 Continuous = 0x4
00395 }
00396
00397 #endregion
00398
00399 #region struct WinMMJoyDetails
00400
00401 struct WinMMJoyDetails
00402 {
00403 public readonly float[] Min, Max;
00404 public PovType PovType;
00405
00406 public WinMMJoyDetails(int num_axes)
00407 {
00408 Min = new float[num_axes];
00409 Max = new float[num_axes];
00410 PovType = PovType.None;
00411 }
00412
00413 public float CalculateOffset(float pos, int axis)
00414 {
00415 float offset = (2 * (pos - Min[axis])) / (Max[axis] - Min[axis]) - 1;
00416 if (offset > 1)
00417 return 1;
00418 else if (offset < -1)
00419 return -1;
00420 else if (offset < 0.001f && offset > -0.001f)
00421 return 0;
00422 else
00423 return offset;
00424 }
00425 }
00426
00427 #endregion
00428 }
00429 }