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.Diagnostics;
00031 using System.Runtime.InteropServices;
00032 using OpenTK.Input;
00033
00034 namespace OpenTK.Platform.X11
00035 {
00036 struct X11JoyDetails { }
00037
00038 sealed class X11Joystick : IJoystickDriver
00039 {
00040 #region Fields
00041
00042 List<JoystickDevice> sticks = new List<JoystickDevice>();
00043 IList<JoystickDevice> sticks_readonly;
00044
00045 bool disposed;
00046
00047 #endregion
00048
00049 #region Constructors
00050
00051 public X11Joystick()
00052 {
00053 sticks_readonly = sticks.AsReadOnly();
00054
00055 int number = 0, max_sticks = 25;
00056 while (number < max_sticks)
00057 {
00058 JoystickDevice stick = OpenJoystick(JoystickPath, number++);
00059 if (stick != null)
00060 {
00061 stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
00062 number, stick.Axis.Count, stick.Button.Count, JoystickPath);
00063 sticks.Add(stick);
00064 }
00065 }
00066
00067 number = 0;
00068 while (number < max_sticks)
00069 {
00070 JoystickDevice stick = OpenJoystick(JoystickPathLegacy, number++);
00071 if (stick != null)
00072 {
00073 stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
00074 number, stick.Axis.Count, stick.Button.Count, JoystickPathLegacy);
00075 sticks.Add(stick);
00076 }
00077 }
00078 }
00079
00080 #endregion
00081
00082 #region IJoystickDriver
00083
00084 public int DeviceCount
00085 {
00086 get { return sticks.Count; }
00087 }
00088
00089 public IList<JoystickDevice> Joysticks
00090 {
00091 get { return sticks_readonly; }
00092 }
00093
00094 public void Poll()
00095 {
00096 JoystickEvent e;
00097
00098 foreach (JoystickDevice js in sticks)
00099 {
00100 unsafe
00101 {
00102 while ((long)UnsafeNativeMethods.read(js.Id, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
00103 {
00104 e.Type &= ~JoystickEventType.Init;
00105
00106 switch (e.Type)
00107 {
00108 case JoystickEventType.Axis:
00109
00110 if (e.Number % 2 == 0)
00111 js.SetAxis((JoystickAxis)e.Number, e.Value / 32767.0f);
00112 else
00113 js.SetAxis((JoystickAxis)e.Number, -e.Value / 32767.0f);
00114 break;
00115
00116 case JoystickEventType.Button:
00117 js.SetButton((JoystickButton)e.Number, e.Value != 0);
00118 break;
00119 }
00120 }
00121 }
00122 }
00123 }
00124
00125 #endregion
00126
00127 #region Private Members
00128
00129 JoystickDevice<X11JoyDetails> OpenJoystick(string base_path, int number)
00130 {
00131 string path = base_path + number.ToString();
00132 JoystickDevice<X11JoyDetails> stick = null;
00133
00134 int fd = -1;
00135 try
00136 {
00137 fd = UnsafeNativeMethods.open(path, OpenFlags.NonBlock);
00138 if (fd == -1)
00139 return null;
00140
00141
00142 int driver_version = 0x00000800;
00143 UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Version, ref driver_version);
00144 if (driver_version < 0x00010000)
00145 return null;
00146
00147
00148 int axes = 0;
00149 UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Axes, ref axes);
00150
00151
00152 int buttons = 0;
00153 UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
00154
00155 stick = new JoystickDevice<X11JoyDetails>(fd, axes, buttons);
00156 Debug.Print("Found joystick on path {0}", path);
00157 }
00158 finally
00159 {
00160 if (stick == null && fd != -1)
00161 UnsafeNativeMethods.close(fd);
00162 }
00163
00164 return stick;
00165 }
00166
00167 #region UnsafeNativeMethods
00168
00169 struct JoystickEvent
00170 {
00171 public uint Time;
00172 public short Value;
00173 public JoystickEventType Type;
00174 public byte Number;
00175 }
00176
00177 [Flags]
00178 enum JoystickEventType : byte
00179 {
00180 Button = 0x01,
00181 Axis = 0x02,
00182 Init = 0x80
00183 }
00184
00185 enum JoystickIoctlCode : uint
00186 {
00187 Version = 0x80046a01,
00188 Axes = 0x80016a11,
00189 Buttons = 0x80016a12
00190 }
00191
00192 static readonly string JoystickPath = "/dev/input/js";
00193 static readonly string JoystickPathLegacy = "/dev/js";
00194
00195 [Flags]
00196 enum OpenFlags
00197 {
00198 NonBlock = 0x00000800
00199 }
00200
00201 static class UnsafeNativeMethods
00202 {
00203 [DllImport("libc", SetLastError = true)]
00204 public static extern int ioctl(int d, JoystickIoctlCode request, ref int data);
00205
00206 [DllImport("libc", SetLastError = true)]
00207 public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags);
00208
00209 [DllImport("libc", SetLastError = true)]
00210 public static extern int close(int fd);
00211
00212 [DllImport("libc", SetLastError = true)]
00213 unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count);
00214 }
00215
00216 #endregion
00217
00218 #endregion
00219
00220 #region IDisposable Members
00221
00222 public void Dispose()
00223 {
00224 Dispose(true);
00225 GC.SuppressFinalize(this);
00226 }
00227
00228 void Dispose(bool manual)
00229 {
00230 if (!disposed)
00231 {
00232 if (manual)
00233 {
00234 }
00235
00236 foreach (JoystickDevice js in sticks)
00237 {
00238 UnsafeNativeMethods.close(js.Id);
00239 }
00240
00241 disposed = true;
00242 }
00243 }
00244
00245 ~X11Joystick()
00246 {
00247 Dispose(false);
00248 }
00249
00250 #endregion
00251 }
00252 }