From 9b43e11ff5d7662c4543c1fcd0fa6ca0477b6e13 Mon Sep 17 00:00:00 2001 From: the_fiddler Date: Sat, 28 Feb 2009 23:11:27 +0000 Subject: [PATCH] Initial joystick support (not public yet). --- Source/OpenTK/Input/IInputDevice.cs | 12 +- Source/OpenTK/Input/IInputDriver.cs | 3 +- Source/OpenTK/Input/IJoystickDriver.cs | 44 +++ Source/OpenTK/Input/IKeyboardDriver.cs | 6 + Source/OpenTK/Input/IMouseDriver.cs | 5 +- Source/OpenTK/Input/InputDriver.cs | 28 +- Source/OpenTK/Input/JoystickDevice.cs | 120 +++++-- Source/OpenTK/Platform/MacOS/CarbonInput.cs | 13 +- Source/OpenTK/Platform/Windows/WMInput.cs | 24 +- Source/OpenTK/Platform/Windows/WinFactory.cs | 3 +- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 297 ++++++++++++++++++ Source/OpenTK/Platform/Windows/WinRawInput.cs | 54 ++-- Source/OpenTK/Platform/X11/X11Input.cs | 9 + Source/OpenTK/Platform/X11/X11Joystick.cs | 243 ++++++++++++++ 14 files changed, 801 insertions(+), 60 deletions(-) create mode 100644 Source/OpenTK/Input/IJoystickDriver.cs create mode 100644 Source/OpenTK/Platform/Windows/WinMMJoystick.cs create mode 100644 Source/OpenTK/Platform/X11/X11Joystick.cs diff --git a/Source/OpenTK/Input/IInputDevice.cs b/Source/OpenTK/Input/IInputDevice.cs index c4c6829f..c27fe1d2 100644 --- a/Source/OpenTK/Input/IInputDevice.cs +++ b/Source/OpenTK/Input/IInputDevice.cs @@ -10,9 +10,19 @@ using System.Text; namespace OpenTK.Input { + /// + /// Defines a common interface for all input devices. + /// public interface IInputDevice { + /// + /// Gets a System.String with a unique description of this IInputDevice instance. + /// string Description { get; } + + /// + /// Gets an OpenTK.Input.InputDeviceType value, representing the device type of this IInputDevice instance. + /// InputDeviceType DeviceType { get; } } @@ -33,6 +43,6 @@ namespace OpenTK.Input /// Device is a Human Interface Device. Joysticks, joypads, pens /// and some specific usb keyboards/mice fall into this category. /// - HID + Hid } } diff --git a/Source/OpenTK/Input/IInputDriver.cs b/Source/OpenTK/Input/IInputDriver.cs index c2ad0a2e..327ee1fa 100644 --- a/Source/OpenTK/Input/IInputDriver.cs +++ b/Source/OpenTK/Input/IInputDriver.cs @@ -10,9 +10,8 @@ using System.Text; namespace OpenTK.Input { - public interface IInputDriver : IKeyboardDriver, IMouseDriver, IDisposable + public interface IInputDriver : IKeyboardDriver, IMouseDriver, IJoystickDriver, IDisposable { - //IList InputDevices { get; } void Poll(); } } diff --git a/Source/OpenTK/Input/IJoystickDriver.cs b/Source/OpenTK/Input/IJoystickDriver.cs new file mode 100644 index 00000000..ecc6bbcd --- /dev/null +++ b/Source/OpenTK/Input/IJoystickDriver.cs @@ -0,0 +1,44 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenTK.Input +{ + /// + /// Defines the interface for JoystickDevice drivers. + /// + public interface IJoystickDriver + { + /// + /// Gets the list of available JoystickDevices. + /// + IList Joysticks { get; } + } +} diff --git a/Source/OpenTK/Input/IKeyboardDriver.cs b/Source/OpenTK/Input/IKeyboardDriver.cs index 368edd28..e14493f9 100644 --- a/Source/OpenTK/Input/IKeyboardDriver.cs +++ b/Source/OpenTK/Input/IKeyboardDriver.cs @@ -10,8 +10,14 @@ using System.Text; namespace OpenTK.Input { + /// + /// Defines the interface for KeyboardDevice drivers. + /// public interface IKeyboardDriver { + /// + /// Gets the list of available KeyboardDevices. + /// IList Keyboard { get; } } } diff --git a/Source/OpenTK/Input/IMouseDriver.cs b/Source/OpenTK/Input/IMouseDriver.cs index 7a47c25f..52abe7af 100644 --- a/Source/OpenTK/Input/IMouseDriver.cs +++ b/Source/OpenTK/Input/IMouseDriver.cs @@ -10,10 +10,13 @@ using System.Text; namespace OpenTK.Input { + /// + /// Defines the interface for MouseDevice drivers. + /// public interface IMouseDriver { /// - /// Gets the list of available mouse devices. + /// Gets the list of available MouseDevices. /// IList Mouse { get; } } diff --git a/Source/OpenTK/Input/InputDriver.cs b/Source/OpenTK/Input/InputDriver.cs index 060b75d8..a1087842 100644 --- a/Source/OpenTK/Input/InputDriver.cs +++ b/Source/OpenTK/Input/InputDriver.cs @@ -59,26 +59,38 @@ namespace OpenTK #region --- IInputDriver Members --- + public void Poll() + { + inputDriver.Poll(); + } + + #endregion + + #region --- IKeyboardDriver Members --- + public IList Keyboard { get { return inputDriver.Keyboard; } } + #endregion + + #region --- IMouseDriver Members --- + public IList Mouse { get { return inputDriver.Mouse; } } - public void Poll() + #endregion + + #region --- IJoystickDriver Members --- + + public IList Joysticks { - inputDriver.Poll(); + get { return inputDriver.Joysticks; } } - /* - int IMouseDriver.RegisterDevices() - { - return inputDriver.RegisterDevices(); - } - */ + #endregion #region --- IDisposable Members --- diff --git a/Source/OpenTK/Input/JoystickDevice.cs b/Source/OpenTK/Input/JoystickDevice.cs index 105e5290..9287a926 100644 --- a/Source/OpenTK/Input/JoystickDevice.cs +++ b/Source/OpenTK/Input/JoystickDevice.cs @@ -1,49 +1,121 @@ -using System; +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + +using System; using System.Collections.Generic; -using System.Text; -using OpenTK.Math; namespace OpenTK.Input { -#if false - /// - /// Represents a joystick device and provides methods to query its state. - /// - public class JoystickDevice : IInputDevice + public abstract class JoystickDevice : IInputDevice { + #region Fields + + int id; string description; - Vector2[] axis_position; + List axis = new List(); + List button = new List(); + IList axis_readonly; + IList button_readonly; - #region --- IInputDevice Members --- + #endregion - /// - /// Gets a string describing this JoystickDevice. - /// + #region Constructors + + internal JoystickDevice(int id, int axes, int buttons) + { + if (axes <= 0) + throw new ArgumentOutOfRangeException("axes"); + + if (buttons <= 0) + throw new ArgumentOutOfRangeException("buttons"); + + Id = id; + axis.AddRange(new float[axes]); + button.AddRange(new bool[buttons]); + + axis_readonly = axis.AsReadOnly(); + button_readonly = button.AsReadOnly(); + } + + #endregion + + #region Public Members + + public IList Axis { get { return axis_readonly; } } + + public IList Button { get { return button_readonly; } } + + #endregion + + #region IInputDevice Members + public string Description { get { return description; } internal set { description = value; } } - /// - /// Gets a value indicating the InputDeviceType of this InputDevice. - /// public InputDeviceType DeviceType { - get { return InputDeviceType.HID; } + get { return InputDeviceType.Hid; } } #endregion - #region --- Public Methods --- + #region Internal Members - //public Vector2 Axis1 - //{ - // get { return axis_position.Clone(); } - // internal set { - //} + internal int Id + { + get { return id; } + set { id = value; } + } + + internal void SetAxis(int num, float @value) + { + axis[num] = @value; + } + + internal void SetButton(int num, bool @value) + { + button[num] = @value; + } #endregion } -#endif + + // Provides platform-specific information about the relevant JoystickDevice. + internal sealed class JoystickDevice : JoystickDevice + { + TDetail details; + + internal JoystickDevice(int id, int axes, int buttons) + : base(id, axes, buttons) + { } + + internal TDetail Details { get { return details; } set { details = value; } } + } } diff --git a/Source/OpenTK/Platform/MacOS/CarbonInput.cs b/Source/OpenTK/Platform/MacOS/CarbonInput.cs index f8cad89a..b8d08b51 100644 --- a/Source/OpenTK/Platform/MacOS/CarbonInput.cs +++ b/Source/OpenTK/Platform/MacOS/CarbonInput.cs @@ -11,13 +11,15 @@ namespace OpenTK.Platform.MacOS { List dummy_keyboard_list = new List(1); List dummy_mice_list = new List(1); + List dummy_joystick_list = new List(1); internal CarbonInput() { dummy_mice_list.Add(new MouseDevice()); dummy_keyboard_list.Add(new KeyboardDevice()); - + dummy_joystick_list.Add(new JoystickDevice(0, 0, 0)); } + #region IInputDriver Members public void Poll() @@ -44,6 +46,15 @@ namespace OpenTK.Platform.MacOS #endregion + #region IJoystickDriver Members + + public IList Joysticks + { + get { return dummy_joystick_list; } + } + + #endregion + #region IDisposable Members public void Dispose() diff --git a/Source/OpenTK/Platform/Windows/WMInput.cs b/Source/OpenTK/Platform/Windows/WMInput.cs index aa864a39..ec6b3a05 100644 --- a/Source/OpenTK/Platform/Windows/WMInput.cs +++ b/Source/OpenTK/Platform/Windows/WMInput.cs @@ -14,11 +14,12 @@ using System.Diagnostics; namespace OpenTK.Platform.Windows { - /// - /// Input driver for legacy (pre XP) Windows platforms. - /// - internal sealed class WMInput : NativeWindow, IInputDriver + // Input driver for legacy (pre XP) Windows platforms. + sealed class WMInput : NativeWindow, IInputDriver { + #region --- Fields --- + + WinMMJoystick joystick_driver = new WinMMJoystick(); // Driver supports only one keyboard and mouse; KeyboardDevice keyboard = new KeyboardDevice(); MouseDevice mouse = new MouseDevice(); @@ -30,6 +31,8 @@ namespace OpenTK.Platform.Windows // Used to distinguish left and right shift keys. static readonly uint ShiftRightScanCode = Functions.MapVirtualKey(VirtualKeys.RSHIFT, 0); + #endregion + #region --- Constructor --- public WMInput(WinWindowInfo parent) @@ -224,6 +227,8 @@ namespace OpenTK.Platform.Windows #endregion + #region --- IInputDriver Members --- + #region IInputDriver Members public void Poll() @@ -251,6 +256,17 @@ namespace OpenTK.Platform.Windows #endregion + #region IJoystickDriver Members + + public IList Joysticks + { + get { return joystick_driver.Joysticks; } + } + + #endregion + + #endregion + #region --- IDisposable Members --- private bool disposed; diff --git a/Source/OpenTK/Platform/Windows/WinFactory.cs b/Source/OpenTK/Platform/Windows/WinFactory.cs index 6d74b4cf..b5f080ed 100644 --- a/Source/OpenTK/Platform/Windows/WinFactory.cs +++ b/Source/OpenTK/Platform/Windows/WinFactory.cs @@ -5,6 +5,7 @@ using System.Text; namespace OpenTK.Platform.Windows { using Graphics; +using OpenTK.Input; class WinFactory : IPlatformFactory { @@ -25,7 +26,7 @@ namespace OpenTK.Platform.Windows return new WinDisplayDeviceDriver(); } - public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool DirectRendering) + public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering) { return new WinGLContext(mode, window, shareContext); } diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs new file mode 100644 index 00000000..23b45771 --- /dev/null +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -0,0 +1,297 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using OpenTK.Input; + +namespace OpenTK.Platform.Windows +{ + sealed class WinMMJoystick : IJoystickDriver + { + #region Fields + + List sticks = new List(); + IList sticks_readonly; + + bool disposed; + + #endregion + + #region Constructors + + public WinMMJoystick() + { + sticks_readonly = sticks.AsReadOnly(); + + int number = 0, max_sticks = 25; + while (number < max_sticks) + { + JoystickDevice stick = OpenJoystick(number++); + if (stick != null) + sticks.Add(stick); + } + } + + #endregion + + #region Private Members + + JoystickDevice OpenJoystick(int number) + { + JoystickDevice stick = null; + + JoyCaps caps; + JoystickError result = UnsafeNativeMethods.joyGetDevCaps(number, out caps, JoyCaps.SizeInBytes); + if (result != JoystickError.NoError) + return null; + + stick = new JoystickDevice(number, caps.NumAxes, caps.NumButtons); + stick.Details = new WinMMJoyDetails(caps.NumAxes); + int axis = 0; + if (axis < caps.NumAxes) + { stick.Details.Min[axis] = caps.XMin; stick.Details.Max[axis] = caps.XMax; axis++; } + if (axis < caps.NumAxes) + { stick.Details.Min[axis] = caps.YMin; stick.Details.Max[axis] = caps.YMax; axis++; } + if (axis < caps.NumAxes) + { stick.Details.Min[axis] = caps.ZMin; stick.Details.Max[axis] = caps.ZMax; axis++; } + if (axis < caps.NumAxes) + { stick.Details.Min[axis] = caps.RMin; stick.Details.Max[axis] = caps.RMax; axis++; } + if (axis < caps.NumAxes) + { stick.Details.Min[axis] = caps.UMin; stick.Details.Max[axis] = caps.UMax; axis++; } + if (axis < caps.NumAxes) + { stick.Details.Min[axis] = caps.VMin; stick.Details.Max[axis] = caps.VMax; axis++; } + + return stick; + } + + #endregion + + #region IJoystickDriver + + public int DeviceCount + { + get { return sticks.Count; } + } + + public IList Joysticks + { + get { return sticks_readonly; } + } + + public void Poll() + { + foreach (JoystickDevice js in sticks) + { + JoyInfoEx info = new JoyInfoEx(); + info.Size = JoyInfoEx.SizeInBytes; + info.Flags = JoystickFlags.All; + UnsafeNativeMethods.joyGetPosEx(js.Id, ref info); + + int axis = 0; + if (axis < js.Axis.Count) + { js.SetAxis(axis, js.Details.CalculateOffset((float)info.XPos, axis)); axis++; } + if (axis < js.Axis.Count) + { js.SetAxis(axis, js.Details.CalculateOffset((float)info.YPos, axis)); axis++; } + if (axis < js.Axis.Count) + { js.SetAxis(axis, js.Details.CalculateOffset((float)info.ZPos, axis)); axis++; } + if (axis < js.Axis.Count) + { js.SetAxis(axis, js.Details.CalculateOffset((float)info.RPos, axis)); axis++; } + if (axis < js.Axis.Count) + { js.SetAxis(axis, js.Details.CalculateOffset((float)info.UPos, axis)); axis++; } + if (axis < js.Axis.Count) + { js.SetAxis(axis, js.Details.CalculateOffset((float)info.VPos, axis)); axis++; } + + int button = 0; + while (button < js.Button.Count) + { + js.SetButton(button, (info.Buttons & (1 << button)) != 0); + button++; + } + } + } + + #endregion + + #region IDisposable + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool manual) + { + if (!disposed) + { + if (manual) + { + } + + disposed = true; + } + } + + ~WinMMJoystick() + { + Dispose(false); + } + + #endregion + + #region UnsafeNativeMethods + + [Flags] + enum JoystickFlags + { + X = 0x1, + Y = 0x2, + Z = 0x4, + R = 0x8, + U = 0x10, + V = 0x20, + Pov = 0x40, + Buttons = 0x80, + All = X | Y | Z | R | U | V | Pov | Buttons + } + + enum JoystickError : uint + { + NoError = 0, + InvalidParameters = 165, + NoCanDo = 166, + Unplugged = 167 + //MM_NoDriver = 6, + //MM_InvalidParameter = 11 + } + + + struct JoyCaps + { + public ushort Mid; + public ushort Pid; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string Pname; + public int XMin; + public int XMax; + public int YMin; + public int YMax; + public int ZMin; + public int ZMax; + public int NumButtons; + public int PeriodMin; + public int PeriodMax; + public int RMin; + public int RMax; + public int UMin; + public int UMax; + public int VMin; + public int VMax; + public int Caps; + public int MaxAxes; + public int NumAxes; + public int MaxButtons; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string RegKey; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string OemVxD; + + public static readonly int SizeInBytes; + + static JoyCaps() + { + SizeInBytes = Marshal.SizeOf(default(JoyCaps)); + } + } + + struct JoyInfoEx + { + public int Size; + [MarshalAs(UnmanagedType.I4)] + public JoystickFlags Flags; + public int XPos; + public int YPos; + public int ZPos; + public int RPos; + public int UPos; + public int VPos; + public uint Buttons; + public uint ButtonNumber; + public int Pov; + uint Reserved1; + uint Reserved2; + + public static readonly int SizeInBytes; + + static JoyInfoEx() + { + SizeInBytes = Marshal.SizeOf(default(JoyInfoEx)); + } + } + + static class UnsafeNativeMethods + { + [DllImport("Winmm.dll")] + public static extern JoystickError joyGetDevCaps(int uJoyID, out JoyCaps pjc, int cbjc); + [DllImport("Winmm.dll")] + public static extern uint joyGetPosEx(int uJoyID, ref JoyInfoEx pji); + } + + #endregion + + #region struct WinMMJoyDetails + + struct WinMMJoyDetails + { + public readonly float[] Min, Max; // Minimum and maximum offset of each axis. + + public WinMMJoyDetails(int num_axes) + { + Min = new float[num_axes]; + Max = new float[num_axes]; + } + + public float CalculateOffset(float pos, int axis) + { + float offset = (2 * (pos - Min[axis])) / (Max[axis] - Min[axis]) - 1; + if (offset > 1) + return 1; + else if (offset < -1) + return -1; + else if (offset < 0.001f && offset > -0.001f) + return 0; + else + return offset; + } + } + + #endregion + } +} diff --git a/Source/OpenTK/Platform/Windows/WinRawInput.cs b/Source/OpenTK/Platform/Windows/WinRawInput.cs index 6bc6865c..73363702 100644 --- a/Source/OpenTK/Platform/Windows/WinRawInput.cs +++ b/Source/OpenTK/Platform/Windows/WinRawInput.cs @@ -18,16 +18,13 @@ using OpenTK.Input; namespace OpenTK.Platform.Windows { - internal class WinRawInput : NativeWindow, IInputDriver + // Not complete. + sealed class WinRawInput : NativeWindow, IInputDriver { - /// - /// Input event data. - /// - private RawInput data = new RawInput(); - /// - /// The total number of input devices connected to this system. - /// - private static int deviceCount; + // Input event data. + RawInput data = new RawInput(); + // The total number of input devices connected to this system. + static int deviceCount; int rawInputStructSize = API.RawInputSize; private WinRawKeyboard keyboardDriver; @@ -134,15 +131,7 @@ namespace OpenTK.Platform.Windows #region --- IInputDriver Members --- - public IList Keyboard - { - get { return keyboardDriver.Keyboard; } - } - - public IList Mouse - { - get { return mouseDriver.Mouse; } - } + #region IInputDriver Members public void Poll() { @@ -211,6 +200,35 @@ namespace OpenTK.Platform.Windows #endregion + #region IKeyboardDriver Members + + public IList Keyboard + { + get { return keyboardDriver.Keyboard; } + } + + #endregion + + #region IMouseDriver Members + + public IList Mouse + { + get { return mouseDriver.Mouse; } + } + + #endregion + + #region IJoystickDriver Members + + public IList Joysticks + { + get { throw new NotImplementedException(); } + } + + #endregion + + #endregion + #region --- IDisposable Members --- private bool disposed; diff --git a/Source/OpenTK/Platform/X11/X11Input.cs b/Source/OpenTK/Platform/X11/X11Input.cs index ca56a493..2924a4ad 100644 --- a/Source/OpenTK/Platform/X11/X11Input.cs +++ b/Source/OpenTK/Platform/X11/X11Input.cs @@ -226,6 +226,15 @@ namespace OpenTK.Platform.X11 #endregion + #region public IList Joysticks + + public IList Joysticks + { + get { throw new NotImplementedException(); } + } + + #endregion + #region public void Poll() /// diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs new file mode 100644 index 00000000..12a96a69 --- /dev/null +++ b/Source/OpenTK/Platform/X11/X11Joystick.cs @@ -0,0 +1,243 @@ +#region License +// +// The Open Toolkit Library License +// +// Copyright (c) 2006 - 2008 the Open Toolkit library, except where noted. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do +// so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using OpenTK.Input; + +namespace OpenTK.Platform.X11 +{ + struct X11JoyDetails { } + + sealed class X11JoystickDriver : IJoystickDriver + { + #region Fields + + List sticks = new List(); + IList sticks_readonly; + + bool disposed; + + #endregion + + #region Constructors + + public X11JoystickDriver() + { + sticks_readonly = sticks.AsReadOnly(); + + int number = 0, max_sticks = 25; + while (number < max_sticks) + { + JoystickDevice stick = OpenJoystick(JoystickPath, number++); + if (stick != null) + sticks.Add(stick); + } + + number = 0; + while (number < max_sticks) + { + JoystickDevice stick = OpenJoystick(JoystickPathLegacy, number++); + if (stick != null) + sticks.Add(stick); + } + } + + #endregion + + #region IJoystickDriver + + public int DeviceCount + { + get { return sticks.Count; } + } + + public IList Joysticks + { + get { return sticks_readonly; } + } + + public void Poll() + { + JoystickEvent e; + + foreach (JoystickDevice js in sticks) + { + unsafe + { + while ((long)UnsafeNativeMethods.read(js.Id, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0) + { + e.Type &= ~JoystickEventType.Init; + + switch (e.Type) + { + case JoystickEventType.Axis: + js.SetAxis(e.Number, e.Value / 32767.0f); + break; + + case JoystickEventType.Button: + js.SetButton(e.Number, e.Value != 0); + break; + } + } + } + } + } + + #endregion + + #region Private Members + + JoystickDevice OpenJoystick(string base_path, int number) + { + string path = base_path + number.ToString(); + JoystickDevice stick = null; + + Debug.Write(String.Format("Attempting to open joystick {0}... ", path)); + + int fd = -1; + try + { + fd = UnsafeNativeMethods.open(path, OpenFlags.NonBlock); + if (fd == -1) + return null; + + // Check joystick driver version (must be 1.0+) + int driver_version = 0x00000800; + UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Version, ref driver_version); + if (driver_version < 0x00010000) + return null; + + // Get number of joystick axes + int axes = 0; + UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Axes, ref axes); + + // Get number of joystick buttons + int buttons = 0; + UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons); + + stick = new JoystickDevice(fd, axes, buttons); + } + finally + { + if (stick == null && fd != -1) + UnsafeNativeMethods.close(fd); + + Debug.Print(stick != null ? "success!" : "failed."); + } + + return stick; + } + + #region UnsafeNativeMethods + + struct JoystickEvent + { + public uint Time; // (u32) event timestamp in milliseconds + public short Value; // (s16) value + public JoystickEventType Type; // (u8) event type + public byte Number; // (u8) axis/button number + } + + [Flags] + enum JoystickEventType : byte + { + Button = 0x01, // button pressed/released + Axis = 0x02, // joystick moved + Init = 0x80 // initial state of device + } + + enum JoystickIoctlCode : uint + { + Version = 0x80046a01, + Axes = 0x80016a11, + Buttons = 0x80016a12 + } + + static readonly string JoystickPath = "/dev/input/js"; + static readonly string JoystickPathLegacy = "/dev/js"; + + [Flags] + enum OpenFlags + { + NonBlock = 0x00000800 + } + + static class UnsafeNativeMethods + { + [DllImport("libc", SetLastError = true)] + public static extern int ioctl(int d, JoystickIoctlCode request, ref int data); + + [DllImport("libc", SetLastError = true)] + public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags); + + [DllImport("libc", SetLastError = true)] + public static extern int close(int fd); + + [DllImport("libc", SetLastError = true)] + unsafe public static extern IntPtr read(int fd, void* buffer, UIntPtr count); + } + + #endregion + + #endregion + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool manual) + { + if (!disposed) + { + if (manual) + { + } + + foreach (JoystickDevice js in sticks) + { + UnsafeNativeMethods.close(js.Id); + } + + disposed = true; + } + } + + ~X11JoystickDriver() + { + Dispose(false); + } + + #endregion + } +}