diff --git a/README.md b/README.md
index 954425db..91325777 100644
--- a/README.md
+++ b/README.md
@@ -1,66 +1,78 @@
OpenTK
======
-
+
The Open Toolkit is an advanced, low-level C# library that wraps OpenGL, OpenGL ES and OpenAL. It is suitable for games, scientific applications and any other project that requires 3d graphics, audio or compute functionality.
-
-This is the official GIT repository of the project:
-
-https://github.com/opentk/opentk
-
-
+
+Project website: http://www.opentk.com/
+
+Official git repository: https://github.com/opentk/opentk
+
+
Features
========
-
-- Create cutting-edge graphics with OpenGL 4.4 and OpenGL ES 3.0.
-
-- Integrate 3d into Windows.Forms, WPF or GTK# applications.
-
-- Write once run everywhere: support for Windows, Mac OS X, Linux, Xamarin.Android and Xamarin.iOS.
-
-- Use strong types and inline documentation to improve your code flow and catch errors sooner.
-
-
+
+- Create cutting-edge graphics with OpenGL 4.4 and OpenGL ES 3.0
+- Spice up your GUI with 3d graphics
+- Improve your code flow with strong types and inline documentation
+- Write once run everywhere!
+
+OpenTK is available on Windows, Linux, Mac OS X, *BSD, SteamOS, Android and iOS. It can be used standalone or integrated into a GUI (Windows.Forms, WPF, GTK+, Qt, VTK, ...)
+
+Binaries and NuGet packages available at http://www.opentk.com
+
+
+Roadmap
+=======
+
+- Merge opentk/opentk (upstream) with mono/opentk (Xamarin)
+- Add Portable Class Library (PCL) target
+- Add multitouch API
+- Add new platforms: NaCL, emscripten, Windows Metro, Ouya, Raspberry PI
+- Improve OpenCL bindings
+- Improve math library
+
+
+Contributing
+============
+
+1. Install git and a C# IDE (see requirements section below)
+2. Fork the _develop_ branch of https://github.com/opentk/opentk
+3. Commit your changes in small, incremental steps with clear descriptions
+4. When ready, issue a Pull Request (PR) against the _develop_ branch of https://github.com/opentk/opentk
+
+For details on coding style and best practices, refer to https://github.com/opentk/opentk/wiki/Contributing
+
+
Requirements
============
-
-OpenTK is designed to be used in an IDE with auto-completion and documentation tooltips:
-- Visual Studio 2005 or higher
-- Xamarin Studio 2.x or higher
-- MonoDevelop 2.x or higher
-- SharpDevelop 3.x or higher
-
-You can develop on your favorite operating system. Compiled binaries can be deployed without recompilation on:
-- Windows
-- Linux
-- Mac OS X
-
-For:
-- Android
-- iOS
-you will need to recompile your code with Xamarin (http://xamarin.com/download)
-
-
+
+- Windows (XP/Vista/7/8), Linux, Mac OS X, *BSD, SteamOS, Android or iOS
+- For graphics, OpenGL drivers or a suitable emulator, such as [ANGLE](https://github.com/opentk/opentk/tree/Dependencies/Readme.txt)
+- For audio, OpenAL drivers or [OpenAL Soft](https://github.com/opentk/opentk/tree/Dependencies/Readme.txt)
+- To develop desktop applications: Visual Studio, Xamarin Studio, MonoDevelop or SharpDevelop
+- To develop Android applications: Xamarin Studio or the Xamarin Extensions for Visual Studio
+- To develop iOS applications: Xamarin Studio and XCode
+
+
Documentation
=============
-
-The Documentation/ folder contains extensive documentation on OpenGL, OpenGL ES and OpenAL. Start with these:
-
-- OpenGL 4.4 API Reference.pdf
-or
-- OpenGL ES 3.0 API Reference.pdf
-
-Your favorite IDE will display inline documentation for all OpenTK APIs. Tutorials can be found in the [OpenTK Manual](http://www.opentk.com/doc)
-
-
+
+Your favorite IDE will display inline documentation for all OpenTK APIs. Additional information can be found in the [OpenTK Manual](http://www.opentk.com/doc) and in the [opentk/Documentation/](https://github.com/opentk/opentk/tree/develop/Documentation) folder.
+
+Technical documentation about the implementation of OpenTK can be found in the [Technical Wiki](https://github.com/opentk/opentk/wiki).
+
+
Need Help?
==========
-
-The community hangs out at the [OpenTK forums](http://www.opentk.com/forum)
-
-If you hit a bug, post an issue on https://github.com/opentk/opentk/issues
-
-
+
+Post your questions at the [OpenTK forums](http://www.opentk.com/forum).
+
+Report bugs at https://github.com/opentk/opentk/issues
+
+
License
=======
-
-The Open Toolkit is distributed under the permissive MIT/X11 license and is absolutely free.
\ No newline at end of file
+
+The Open Toolkit is distributed under the permissive MIT/X11 license and is absolutely free.
+
+http://www.opentk.com/project/license
diff --git a/Source/OpenTK/GameWindow.cs b/Source/OpenTK/GameWindow.cs
index 559c90b1..17bb445d 100644
--- a/Source/OpenTK/GameWindow.cs
+++ b/Source/OpenTK/GameWindow.cs
@@ -78,6 +78,8 @@ namespace OpenTK
const double MaxFrequency = 500.0; // Frequency cap for Update/RenderFrame events
readonly Stopwatch watch = new Stopwatch();
+ readonly IJoystickDriver LegacyJoystick =
+ Factory.Default.CreateLegacyJoystickDriver();
IGraphicsContext glContext;
@@ -576,9 +578,10 @@ namespace OpenTK
///
/// Gets a readonly IList containing all available OpenTK.Input.JoystickDevices.
///
+ [Obsolete("Use OpenTK.Input.Joystick and GamePad instead")]
public IList Joysticks
{
- get { return InputDriver.Joysticks; }
+ get { return LegacyJoystick.Joysticks; }
}
#endregion
diff --git a/Source/OpenTK/INativeWindow.cs b/Source/OpenTK/INativeWindow.cs
index 9621f6f4..b1df51fa 100644
--- a/Source/OpenTK/INativeWindow.cs
+++ b/Source/OpenTK/INativeWindow.cs
@@ -129,7 +129,7 @@ namespace OpenTK
///
/// This property is deprecated and should not be used.
///
- [Obsolete]
+ [Obsolete("Use OpenTK.Input.Mouse/Keybord/Joystick/GamePad instead.")]
OpenTK.Input.IInputDriver InputDriver { get; }
///
diff --git a/Source/OpenTK/Input/JoystickDevice.cs b/Source/OpenTK/Input/JoystickDevice.cs
index 8e239f56..0467ce2d 100644
--- a/Source/OpenTK/Input/JoystickDevice.cs
+++ b/Source/OpenTK/Input/JoystickDevice.cs
@@ -130,22 +130,28 @@ namespace OpenTK.Input
internal void SetAxis(JoystickAxis axis, float @value)
{
- move_args.Axis = axis;
- move_args.Delta = move_args.Value - @value;
- axis_collection[axis] = move_args.Value = @value;
- Move(this, move_args);
+ if ((int)axis < axis_collection.Count)
+ {
+ move_args.Axis = axis;
+ move_args.Delta = move_args.Value - @value;
+ axis_collection[axis] = move_args.Value = @value;
+ Move(this, move_args);
+ }
}
internal void SetButton(JoystickButton button, bool @value)
{
- if (button_collection[button] != @value)
+ if ((int)button < button_collection.Count)
{
- button_args.Button = button;
- button_collection[button] = button_args.Pressed = @value;
- if (@value)
- ButtonDown(this, button_args);
- else
- ButtonUp(this, button_args);
+ if (button_collection[button] != @value)
+ {
+ button_args.Button = button;
+ button_collection[button] = button_args.Pressed = @value;
+ if (@value)
+ ButtonDown(this, button_args);
+ else
+ ButtonUp(this, button_args);
+ }
}
}
diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj
index d9b969c9..8c3931fc 100644
--- a/Source/OpenTK/OpenTK.csproj
+++ b/Source/OpenTK/OpenTK.csproj
@@ -166,6 +166,7 @@
+
Code
@@ -798,6 +799,8 @@
+
+
diff --git a/Source/OpenTK/Platform/Factory.cs b/Source/OpenTK/Platform/Factory.cs
index e49eb36b..571deb44 100644
--- a/Source/OpenTK/Platform/Factory.cs
+++ b/Source/OpenTK/Platform/Factory.cs
@@ -33,6 +33,7 @@ using System.Text;
namespace OpenTK.Platform
{
using Graphics;
+ using Input;
sealed class Factory : IPlatformFactory
{
@@ -134,27 +135,32 @@ namespace OpenTK.Platform
return default_implementation.CreateGraphicsMode();
}
- public OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
+ public IKeyboardDriver2 CreateKeyboardDriver()
{
return default_implementation.CreateKeyboardDriver();
}
- public OpenTK.Input.IMouseDriver2 CreateMouseDriver()
+ public IMouseDriver2 CreateMouseDriver()
{
return default_implementation.CreateMouseDriver();
}
- public OpenTK.Input.IGamePadDriver CreateGamePadDriver()
+ public IGamePadDriver CreateGamePadDriver()
{
return default_implementation.CreateGamePadDriver();
}
- public Input.IJoystickDriver2 CreateJoystickDriver()
+ public IJoystickDriver2 CreateJoystickDriver()
{
return default_implementation.CreateJoystickDriver();
}
- class UnsupportedPlatform : IPlatformFactory
+ public IJoystickDriver CreateLegacyJoystickDriver()
+ {
+ return default_implementation.CreateLegacyJoystickDriver();
+ }
+
+ class UnsupportedPlatform : PlatformFactoryBase
{
#region Fields
@@ -165,92 +171,51 @@ namespace OpenTK.Platform
#region IPlatformFactory Members
- public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
+ public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
throw new PlatformNotSupportedException(error_string);
}
- public IDisplayDeviceDriver CreateDisplayDeviceDriver()
+ public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
throw new PlatformNotSupportedException(error_string);
}
- public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new PlatformNotSupportedException(error_string);
}
- public IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new PlatformNotSupportedException(error_string);
}
- public IGraphicsContext CreateESContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags)
+ public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
throw new PlatformNotSupportedException(error_string);
}
- public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
+ public override IGraphicsMode CreateGraphicsMode()
{
throw new PlatformNotSupportedException(error_string);
}
- public IGraphicsMode CreateGraphicsMode()
+ public override IKeyboardDriver2 CreateKeyboardDriver()
{
throw new PlatformNotSupportedException(error_string);
}
- public OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
+ public override IMouseDriver2 CreateMouseDriver()
{
throw new PlatformNotSupportedException(error_string);
}
- public OpenTK.Input.IMouseDriver2 CreateMouseDriver()
+ public override IJoystickDriver2 CreateJoystickDriver()
{
throw new PlatformNotSupportedException(error_string);
}
- public OpenTK.Input.IGamePadDriver CreateGamePadDriver()
- {
- throw new PlatformNotSupportedException(error_string);
- }
-
- public Input.IJoystickDriver2 CreateJoystickDriver()
- {
- throw new PlatformNotSupportedException(error_string);
- }
-
- #endregion
-
- #region IDisposable Members
-
- void Dispose(bool manual)
- {
- if (!disposed)
- {
- if (manual)
- {
- // nothing to do
- }
- else
- {
- Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
- }
- disposed = true;
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~UnsupportedPlatform()
- {
- Dispose(false);
- }
-
#endregion
}
diff --git a/Source/OpenTK/Platform/IPlatformFactory.cs b/Source/OpenTK/Platform/IPlatformFactory.cs
index c59654f3..c5abb9c5 100644
--- a/Source/OpenTK/Platform/IPlatformFactory.cs
+++ b/Source/OpenTK/Platform/IPlatformFactory.cs
@@ -54,5 +54,7 @@ namespace OpenTK.Platform
OpenTK.Input.IGamePadDriver CreateGamePadDriver();
Input.IJoystickDriver2 CreateJoystickDriver();
+
+ Input.IJoystickDriver CreateLegacyJoystickDriver();
}
}
diff --git a/Source/OpenTK/Platform/LegacyJoystickDriver.cs b/Source/OpenTK/Platform/LegacyJoystickDriver.cs
new file mode 100644
index 00000000..4b2f39cc
--- /dev/null
+++ b/Source/OpenTK/Platform/LegacyJoystickDriver.cs
@@ -0,0 +1,108 @@
+#region License
+//
+// LegacyJoystickDriver.cs
+//
+// Author:
+// Stefanos A.
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// 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 OpenTK.Input;
+
+namespace OpenTK.Platform
+{
+ internal class LegacyJoystickDriver : IJoystickDriver
+ {
+ static readonly string ConnectedName = "Connected Joystick";
+ static readonly string DisconnectedName = "Disconnected Joystick";
+ readonly List joysticks = new List();
+ readonly IList joysticks_readonly;
+
+ class LegacyJoystickDevice : JoystickDevice
+ {
+ public LegacyJoystickDevice(int id, int axes, int buttons)
+ : base(id, axes, buttons)
+ { }
+ }
+
+ internal LegacyJoystickDriver()
+ {
+ joysticks_readonly = joysticks.AsReadOnly();
+ for (int i = 0; i < 4; i++)
+ {
+ joysticks.Add(new LegacyJoystickDevice(i, 0, 0));
+ joysticks[i].Description = DisconnectedName;
+ }
+ }
+
+ public void Poll()
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ JoystickCapabilities caps = Joystick.GetCapabilities(i);
+ if (caps.IsConnected && joysticks[i].Description == DisconnectedName)
+ {
+ // New joystick connected
+ joysticks[i] = new LegacyJoystickDevice(i, caps.AxisCount, caps.ButtonCount);
+ //device.Description = Joystick.GetName(i);
+ joysticks[i].Description = ConnectedName;
+
+ }
+ else if (!caps.IsConnected && joysticks[i].Description != DisconnectedName)
+ {
+ // Joystick disconnected
+ joysticks[i] = new LegacyJoystickDevice(i, 0, 0);
+ joysticks[i].Description = DisconnectedName;
+ }
+
+ JoystickState state = Joystick.GetState(i);
+ for (int axis_index = 0; axis_index < (int)caps.AxisCount; axis_index++)
+ {
+ JoystickAxis axis = JoystickAxis.Axis0 + axis_index;
+ joysticks[i].SetAxis(axis, state.GetAxis(axis));
+ }
+ for (int button_index = 0; button_index < (int)caps.ButtonCount; button_index++)
+ {
+ JoystickButton button = JoystickButton.Button0 + button_index;
+ joysticks[i].SetButton(button, state.GetButton(button) == ButtonState.Pressed);
+ }
+ }
+ }
+
+ #region IJoystickDriver Members
+
+ public IList Joysticks
+ {
+ get
+ {
+ Poll();
+ return joysticks_readonly;
+ }
+ }
+
+ #endregion
+ }
+}
+
diff --git a/Source/OpenTK/Platform/MacOS/MacOSFactory.cs b/Source/OpenTK/Platform/MacOS/MacOSFactory.cs
index 697f2352..8a72db56 100644
--- a/Source/OpenTK/Platform/MacOS/MacOSFactory.cs
+++ b/Source/OpenTK/Platform/MacOS/MacOSFactory.cs
@@ -35,38 +35,33 @@ namespace OpenTK.Platform.MacOS
{
using Graphics;
- class MacOSFactory : IPlatformFactory
+ class MacOSFactory : PlatformFactoryBase
{
- #region Fields
-
- bool disposed;
readonly IInputDriver2 InputDriver = new HIDInput();
- #endregion
-
#region IPlatformFactory Members
- public virtual INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
+ public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
return new CarbonGLNative(x, y, width, height, title, mode, options, device);
}
- public virtual IDisplayDeviceDriver CreateDisplayDeviceDriver()
+ public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new QuartzDisplayDeviceDriver();
}
- public virtual IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new AglContext(mode, window, shareContext);
}
- public virtual IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new AglContext(handle, window, shareContext);
}
- public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
+ public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
@@ -74,27 +69,17 @@ namespace OpenTK.Platform.MacOS
};
}
- public virtual IGraphicsMode CreateGraphicsMode()
- {
- throw new NotSupportedException();
- }
-
- public virtual OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
+ public override IKeyboardDriver2 CreateKeyboardDriver()
{
return InputDriver.KeyboardDriver;
}
- public virtual OpenTK.Input.IMouseDriver2 CreateMouseDriver()
+ public override IMouseDriver2 CreateMouseDriver()
{
return InputDriver.MouseDriver;
}
- public virtual OpenTK.Input.IGamePadDriver CreateGamePadDriver()
- {
- return InputDriver.GamePadDriver;
- }
-
- public IJoystickDriver2 CreateJoystickDriver()
+ public override IJoystickDriver2 CreateJoystickDriver()
{
return InputDriver.JoystickDriver;
}
@@ -103,33 +88,19 @@ namespace OpenTK.Platform.MacOS
#region IDisposable Members
- void Dispose(bool manual)
+ protected override void Dispose(bool manual)
{
- if (!disposed)
+ if (!IsDisposed)
{
if (manual)
{
InputDriver.Dispose();
}
- else
- {
- Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
- }
- disposed = true;
+
+ base.Dispose(manual);
}
}
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~MacOSFactory()
- {
- Dispose(false);
- }
-
#endregion
}
}
diff --git a/Source/OpenTK/Platform/PlatformFactoryBase.cs b/Source/OpenTK/Platform/PlatformFactoryBase.cs
new file mode 100644
index 00000000..d85c645b
--- /dev/null
+++ b/Source/OpenTK/Platform/PlatformFactoryBase.cs
@@ -0,0 +1,120 @@
+#region License
+//
+// PlatformFactoryBase.cs
+//
+// Author:
+// Stefanos A.
+//
+// Copyright (c) 2006-2014 Stefanos Apostolopoulos
+//
+// 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.Diagnostics;
+using OpenTK.Graphics;
+using OpenTK.Input;
+
+namespace OpenTK.Platform
+{
+ /// \internal
+ ///
+ /// Implements IPlatformFactory functionality that is common
+ /// for all platform backends. IPlatformFactory implementations
+ /// should inherit from this class.
+ ///
+ abstract class PlatformFactoryBase : IPlatformFactory
+ {
+ protected bool IsDisposed;
+
+ public PlatformFactoryBase()
+ {
+ }
+
+ #region IPlatformFactory Members
+
+ public abstract INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device);
+
+ public abstract IDisplayDeviceDriver CreateDisplayDeviceDriver();
+
+ public abstract IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags);
+
+ public virtual IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ {
+ throw new NotImplementedException();
+ }
+
+ public abstract GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext();
+
+ public virtual IGraphicsMode CreateGraphicsMode()
+ {
+ throw new NotSupportedException();
+ }
+
+ public abstract IKeyboardDriver2 CreateKeyboardDriver();
+
+ public abstract IMouseDriver2 CreateMouseDriver();
+
+ public virtual IGamePadDriver CreateGamePadDriver()
+ {
+ return new MappedGamePadDriver();
+ }
+
+ public abstract IJoystickDriver2 CreateJoystickDriver();
+
+ public virtual IJoystickDriver CreateLegacyJoystickDriver()
+ {
+ return new LegacyJoystickDriver();
+ }
+
+ #endregion
+
+ #region IDisposable implementation
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool manual)
+ {
+ if (!IsDisposed)
+ {
+ if (manual)
+ {
+ }
+ else
+ {
+ Debug.Print("[OpenTK] {0} leaked, did you forget to call Dispose()?", GetType());
+ }
+ IsDisposed = true;
+ }
+ }
+
+ ~PlatformFactoryBase()
+ {
+ Dispose(false);
+ }
+
+ #endregion
+ }
+}
+
diff --git a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs
index b8015f6b..25a3c6d9 100644
--- a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs
+++ b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs
@@ -32,10 +32,9 @@ using OpenTK.Input;
namespace OpenTK.Platform.SDL2
{
- class Sdl2Factory : IPlatformFactory
+ class Sdl2Factory : PlatformFactoryBase
{
readonly Sdl2InputDriver InputDriver = new Sdl2InputDriver();
- bool disposed;
///
/// Gets or sets a value indicating whether to use SDL2 fullscreen-desktop mode
@@ -56,27 +55,27 @@ namespace OpenTK.Platform.SDL2
#region IPlatformFactory implementation
- public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
+ public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
return new Sdl2NativeWindow(x, y, width, height, title, options, device, InputDriver);
}
- public IDisplayDeviceDriver CreateDisplayDeviceDriver()
+ public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new Sdl2DisplayDeviceDriver();
}
- virtual public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new Sdl2GraphicsContext(mode, window, shareContext, major, minor, flags);
}
- public IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new NotImplementedException();
}
- public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
+ public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
@@ -84,27 +83,17 @@ namespace OpenTK.Platform.SDL2
};
}
- public IGraphicsMode CreateGraphicsMode()
- {
- return new Sdl2GraphicsMode();
- }
-
- public IKeyboardDriver2 CreateKeyboardDriver()
+ public override IKeyboardDriver2 CreateKeyboardDriver()
{
return InputDriver.KeyboardDriver;
}
- public IMouseDriver2 CreateMouseDriver()
+ public override IMouseDriver2 CreateMouseDriver()
{
return InputDriver.MouseDriver;
}
- public IGamePadDriver CreateGamePadDriver()
- {
- return InputDriver.GamePadDriver;
- }
-
- public IJoystickDriver2 CreateJoystickDriver()
+ public override IJoystickDriver2 CreateJoystickDriver()
{
return InputDriver.JoystickDriver;
}
@@ -113,34 +102,19 @@ namespace OpenTK.Platform.SDL2
#region IDisposable Members
- void Dispose(bool manual)
+ protected override void Dispose(bool manual)
{
- if (!disposed)
+ if (!IsDisposed)
{
if (manual)
{
- Debug.Print("Disposing {0}", GetType());
InputDriver.Dispose();
}
- else
- {
- Debug.WriteLine("Sdl2Factory leaked, did you forget to call Dispose()?");
- }
- disposed = true;
+
+ base.Dispose(manual);
}
}
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~Sdl2Factory()
- {
- Dispose(false);
- }
-
#endregion
}
}
diff --git a/Source/OpenTK/Platform/Windows/WinFactory.cs b/Source/OpenTK/Platform/Windows/WinFactory.cs
index 4fa46e2e..877377ab 100644
--- a/Source/OpenTK/Platform/Windows/WinFactory.cs
+++ b/Source/OpenTK/Platform/Windows/WinFactory.cs
@@ -37,9 +37,8 @@ using OpenTK.Input;
namespace OpenTK.Platform.Windows
{
- class WinFactory : IPlatformFactory
+ class WinFactory : PlatformFactoryBase
{
- bool disposed;
readonly object SyncRoot = new object();
IInputDriver2 inputDriver;
@@ -83,27 +82,27 @@ namespace OpenTK.Platform.Windows
#region IPlatformFactory Members
- public virtual INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
+ public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
return new WinGLNative(x, y, width, height, title, options, device);
}
- public virtual IDisplayDeviceDriver CreateDisplayDeviceDriver()
+ public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new WinDisplayDeviceDriver();
}
- public virtual IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new WinGLContext(mode, (WinWindowInfo)window, shareContext, major, minor, flags);
}
- public virtual IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new WinGLContext(handle, (WinWindowInfo)window, shareContext, major, minor, flags);
}
- public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
+ public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
@@ -111,27 +110,22 @@ namespace OpenTK.Platform.Windows
};
}
- public virtual IGraphicsMode CreateGraphicsMode()
- {
- throw new NotSupportedException();
- }
-
- public virtual OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
+ public override OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
{
return InputDriver.KeyboardDriver;
}
- public virtual OpenTK.Input.IMouseDriver2 CreateMouseDriver()
+ public override OpenTK.Input.IMouseDriver2 CreateMouseDriver()
{
return InputDriver.MouseDriver;
}
- public virtual OpenTK.Input.IGamePadDriver CreateGamePadDriver()
+ public override OpenTK.Input.IGamePadDriver CreateGamePadDriver()
{
return InputDriver.GamePadDriver;
}
- public IJoystickDriver2 CreateJoystickDriver()
+ public override IJoystickDriver2 CreateJoystickDriver()
{
return InputDriver.JoystickDriver;
}
@@ -155,33 +149,19 @@ namespace OpenTK.Platform.Windows
#region IDisposable Members
- void Dispose(bool manual)
+ protected override void Dispose(bool manual)
{
- if (!disposed)
+ if (!IsDisposed)
{
if (manual)
{
InputDriver.Dispose();
}
- else
- {
- Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
- }
- disposed = true;
+
+ base.Dispose(manual);
}
}
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~WinFactory()
- {
- Dispose(false);
- }
-
#endregion
}
}
diff --git a/Source/OpenTK/Platform/X11/Bindings/INotify.cs b/Source/OpenTK/Platform/X11/Bindings/INotify.cs
new file mode 100644
index 00000000..662b12ab
--- /dev/null
+++ b/Source/OpenTK/Platform/X11/Bindings/INotify.cs
@@ -0,0 +1,210 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace OpenTK.Platform.X11.Bindings
+{
+ // Fully implemented but not currently used by OpenTK
+ // See System.IO.FileSystemWatcher for a cross-platform alternative
+#if false
+ class INotify
+ {
+ const string lib = "";
+
+ ///
+ /// Create and initialize inotify instance
+ ///
+ ///
+ [DllImport(lib, EntryPoint = "inotify_init", ExactSpelling = true)]
+ public static extern int Init();
+
+ ///
+ /// Create and initialize inotify instance with specified flags
+ ///
+ /// See
+ /// A System.Int32 handle to a inotify instance
+ [DllImport(lib, EntryPoint = "inotify_init1", ExactSpelling = true)]
+ public static extern int Init(INotifyFlags flags);
+
+ ///
+ /// Add watch of object pathname to inotify instance fd. Notify about
+ /// events specified by mask
+ ///
+ [DllImport(lib, EntryPoint = "inotify_add_watch", ExactSpelling = true)]
+ public static extern int AddWatch(int fd, string pathname, INotifyFlags mask);
+
+ ///
+ /// Remove the watch specified by wd from the inotify instance fd
+ ///
+ [DllImport(lib, EntryPoint = "inotify_rm_watch", ExactSpelling = true)]
+ public static extern int RemoveWatch(int fd, int wd);
+ }
+
+ ///
+ /// Describes an INotify event
+ ///
+ struct INotifyEvent
+ {
+ ///
+ /// Watch descriptor for wd parameter of INotify methods
+ ///
+ public int WatchDescriptor;
+
+ ///
+ /// Watch mask for mask parameter of INotify methods
+ ///
+ public INotifyFlags WatchMask;
+
+ ///
+ /// Cookie to synchronize two events
+ ///
+ public uint Cookie;
+
+ ///
+ /// Length (including NULs) of name
+ ///
+ public uint Length;
+
+ ///
+ ///
+ ///
+ public IntPtr Name;
+ }
+
+ ///
+ /// Flags for the parameter of
+ ///
+ [Flags]
+ enum INotifyInitFlags
+ {
+ CloExec = 02000000,
+ NonBlock = 04000
+ }
+
+ /// \internal
+ ///
+ /// Supported events suitable for MASK parameter of AddWatch.
+ ///
+ [Flags]
+ enum INotifyFlags
+ {
+ ///
+ /// File was accessed
+ ///
+ Access = 0x00000001,
+
+ ///
+ /// File was modified
+ ///
+ Modify = 0x00000002,
+
+ ///
+ /// Metadata changed
+ ///
+ Attrib = 0x00000004,
+
+ ///
+ /// Writable file was closed
+ ///
+ CloseWrite = 0x00000008,
+
+ ///
+ /// Unwritable file closed
+ ///
+ CloseNoWrite = 0x00000010,
+
+ ///
+ /// File closed
+ ///
+ Close = CloseWrite | CloseNoWrite,
+
+ ///
+ /// File was opened
+ ///
+ Open = 0x00000020,
+
+ ///
+ /// File was moved from X
+ ///
+ MovedFrom = 0x00000040,
+
+ ///
+ /// File was moved to Y
+ ///
+ MovedTo = 0x00000080,
+
+ ///
+ /// File was moved
+ ///
+ Move = MovedFrom | MovedTo,
+
+ ///
+ /// Subfile was created
+ ///
+ Create = 0x00000100,
+
+ ///
+ /// Subfile was deleted
+ ///
+ Delete = 0x00000200,
+
+ ///
+ /// Self was deleted
+ ///
+ DeleteSelf = 0x00000400,
+
+ ///
+ /// Self was moved
+ ///
+ MoveSelf = 0x00000800,
+
+ ///
+ /// Backing fs was unmounted
+ ///
+ Unmount = 0x00002000,
+
+ ///
+ /// Event queue overflowed
+ ///
+ QueueOverflow = 0x00004000,
+
+ ///
+ /// File was ignored
+ ///
+ Ignored = 0x00008000,
+
+ ///
+ /// Only watch the path if it is a directory
+ ///
+ OnlyDirectory = 0x01000000,
+
+ ///
+ /// Do not follow symlinks
+ ///
+ DontFollow = 0x02000000,
+
+ ///
+ /// Add to the mask of an already existing watch
+ ///
+ MaskAdd = 0x20000000,
+
+ ///
+ /// Event occurred against dir
+ ///
+ IsDirectory = 0x40000000,
+
+ ///
+ /// Only send event once
+ ///
+ Oneshot = 0x80000000,
+
+ ///
+ /// All events which a program can wait on
+ ///
+ AllEvents =
+ Access | Modify | Attrib | Close | Open | Move |
+ Create | Delete | DeleteSelf | MoveSelf
+ }
+#endif
+}
diff --git a/Source/OpenTK/Platform/X11/X11Factory.cs b/Source/OpenTK/Platform/X11/X11Factory.cs
index 0fb80058..985f21cb 100644
--- a/Source/OpenTK/Platform/X11/X11Factory.cs
+++ b/Source/OpenTK/Platform/X11/X11Factory.cs
@@ -28,10 +28,11 @@
using System;
using System.Diagnostics;
using OpenTK.Graphics;
+using OpenTK.Input;
namespace OpenTK.Platform.X11
{
- class X11Factory : IPlatformFactory
+ class X11Factory : PlatformFactoryBase
{
bool disposed;
@@ -47,27 +48,27 @@ namespace OpenTK.Platform.X11
#region IPlatformFactory Members
- public virtual INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
+ public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
return new X11GLNative(x, y, width, height, title, mode, options, device);
}
- public virtual IDisplayDeviceDriver CreateDisplayDeviceDriver()
+ public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new X11DisplayDevice();
}
- public virtual IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new X11GLContext(mode, window, shareContext, directRendering, major, minor, flags);
}
- public virtual IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new X11GLContext(handle, window, shareContext, directRendering, major, minor, flags);
}
- public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
+ public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
@@ -75,17 +76,17 @@ namespace OpenTK.Platform.X11
};
}
- public virtual IGraphicsMode CreateGraphicsMode()
+ public override IGraphicsMode CreateGraphicsMode()
{
throw new NotSupportedException();
}
- public virtual OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
+ public override IKeyboardDriver2 CreateKeyboardDriver()
{
return new X11Keyboard();
}
- public virtual OpenTK.Input.IMouseDriver2 CreateMouseDriver()
+ public override IMouseDriver2 CreateMouseDriver()
{
if (XI2Mouse.IsSupported(IntPtr.Zero))
return new XI2Mouse(); // Requires xorg 1.7 or higher.
@@ -93,48 +94,11 @@ namespace OpenTK.Platform.X11
return new X11Mouse(); // Always supported.
}
- public virtual OpenTK.Input.IGamePadDriver CreateGamePadDriver()
+ public override IJoystickDriver2 CreateJoystickDriver()
{
return new X11Joystick();
}
- public virtual OpenTK.Input.IJoystickDriver2 CreateJoystickDriver()
- {
- return new X11Joystick();
- }
-
-
- #endregion
-
- #region IDisposable Members
-
- void Dispose(bool manual)
- {
- if (!disposed)
- {
- if (manual)
- {
- // nothing to do
- }
- else
- {
- Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
- }
- disposed = true;
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~X11Factory()
- {
- Dispose(false);
- }
-
#endregion
}
}
diff --git a/Source/OpenTK/Platform/X11/X11Input.cs b/Source/OpenTK/Platform/X11/X11Input.cs
index a8393beb..3847745f 100644
--- a/Source/OpenTK/Platform/X11/X11Input.cs
+++ b/Source/OpenTK/Platform/X11/X11Input.cs
@@ -24,8 +24,6 @@ namespace OpenTK.Platform.X11
///
internal sealed class X11Input : IInputDriver
{
- X11Joystick joystick_driver = new X11Joystick();
- //X11WindowInfo window;
KeyboardDevice keyboard = new KeyboardDevice();
MouseDevice mouse = new MouseDevice();
List dummy_keyboard_list = new List(1);
@@ -96,57 +94,6 @@ namespace OpenTK.Platform.X11
#endregion
- #region private void InternalPoll()
-#if false
- private void InternalPoll()
- {
- X11.XEvent e = new XEvent();
- try
- {
- while (!disposed)
- {
- Functions.XMaskEvent(window.Display,
- EventMask.PointerMotionMask | EventMask.PointerMotionHintMask |
- EventMask.ButtonPressMask | EventMask.ButtonReleaseMask |
- EventMask.KeyPressMask | EventMask.KeyReleaseMask |
- EventMask.StructureNotifyMask, ref e);
-
- if (disposed)
- return;
-
- switch (e.type)
- {
- case XEventName.KeyPress:
- case XEventName.KeyRelease:
- keyboardDriver.ProcessKeyboardEvent(ref e.KeyEvent);
- break;
-
- case XEventName.ButtonPress:
- case XEventName.ButtonRelease:
- mouseDriver.ProcessButton(ref e.ButtonEvent);
- break;
-
- case XEventName.MotionNotify:
- mouseDriver.ProcessMotion(ref e.MotionEvent);
- break;
-
- case XEventName.DestroyNotify:
- Functions.XPutBackEvent(window.Display, ref e);
- Functions.XAutoRepeatOn(window.Display);
- return;
- }
- }
- }
- catch (ThreadAbortException expt)
- {
- Functions.XUnmapWindow(window.Display, window.Handle);
- Functions.XDestroyWindow(window.Display, window.Handle);
- return;
- }
- }
-#endif
- #endregion
-
#region TranslateKey
internal bool TranslateKey(ref XKeyEvent e, out Key key)
@@ -242,11 +189,9 @@ namespace OpenTK.Platform.X11
#endregion
- #region public IList Joysticks
-
public IList Joysticks
{
- get { return joystick_driver.Joysticks; }
+ get { throw new NotImplementedException(); }
}
#endregion
@@ -258,13 +203,10 @@ namespace OpenTK.Platform.X11
///
public void Poll()
{
- joystick_driver.Poll();
}
#endregion
- #endregion
-
#region --- IDisposable Members ---
public void Dispose()
diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs
index cbab7099..5aaf60d3 100644
--- a/Source/OpenTK/Platform/X11/X11Joystick.cs
+++ b/Source/OpenTK/Platform/X11/X11Joystick.cs
@@ -1,4 +1,4 @@
-#region License
+#region License
//
// The Open Toolkit Library License
//
@@ -28,20 +28,31 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using OpenTK.Input;
namespace OpenTK.Platform.X11
{
- struct X11JoyDetails { }
+ struct X11JoyDetails
+ {
+ public Guid Guid;
+ public int FileDescriptor;
+ public JoystickState State;
+ }
- sealed class X11Joystick : IJoystickDriver, IJoystickDriver2, IGamePadDriver
+ sealed class X11Joystick : IJoystickDriver2
{
#region Fields
- List sticks = new List();
- IList sticks_readonly;
+ readonly object sync = new object();
+
+ readonly FileSystemWatcher watcher = new FileSystemWatcher(JoystickPath);
+ readonly FileSystemWatcher watcher_legacy = new FileSystemWatcher(JoystickPathLegacy);
+
+ readonly Dictionary index_to_stick = new Dictionary();
+ List> sticks = new List>();
bool disposed;
@@ -51,74 +62,96 @@ namespace OpenTK.Platform.X11
public X11Joystick()
{
- sticks_readonly = sticks.AsReadOnly();
+ watcher.Created += JoystickAdded;
+ watcher.Deleted += JoystickRemoved;
+ watcher.EnableRaisingEvents = true;
- int number = 0, max_sticks = 25;
- while (number < max_sticks)
- {
- JoystickDevice stick = OpenJoystick(JoystickPath, number++);
- if (stick != null)
- {
- //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
- //number, stick.Axis.Count, stick.Button.Count, JoystickPath);
- sticks.Add(stick);
- }
- }
+ watcher_legacy.Created += JoystickAdded;
+ watcher_legacy.Deleted += JoystickRemoved;
+ watcher_legacy.EnableRaisingEvents = true;
- number = 0;
- while (number < max_sticks)
- {
- JoystickDevice stick = OpenJoystick(JoystickPathLegacy, number++);
- if (stick != null)
- {
- //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
- //number, stick.Axis.Count, stick.Button.Count, JoystickPathLegacy);
- sticks.Add(stick);
- }
- }
+ OpenJoysticks();
}
#endregion
- #region IJoystickDriver
+ #region Private Members
- public int DeviceCount
+ void OpenJoysticks()
{
- get { return sticks.Count; }
- }
-
- public IList Joysticks
- {
- get { Poll(); return sticks_readonly; }
- }
-
- public void Poll()
- {
- JoystickEvent e;
-
- foreach (JoystickDevice js in sticks)
+ lock (sync)
{
- unsafe
+ foreach (string file in Directory.GetFiles(JoystickPath))
{
- while ((long)UnsafeNativeMethods.read(js.Id, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
+ JoystickDevice stick = OpenJoystick(file);
+ if (stick != null)
{
- e.Type &= ~JoystickEventType.Init;
+ //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
+ //number, stick.Axis.Count, stick.Button.Count, JoystickPath);
+ sticks.Add(stick);
+ }
+ }
- switch (e.Type)
+ foreach (string file in Directory.GetFiles(JoystickPathLegacy))
+ {
+ JoystickDevice stick = OpenJoystick(file);
+ if (stick != null)
+ {
+ //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
+ //number, stick.Axis.Count, stick.Button.Count, JoystickPathLegacy);
+ sticks.Add(stick);
+ }
+ }
+ }
+ }
+
+ int GetJoystickNumber(string path)
+ {
+ if (path.StartsWith("js"))
+ {
+ int num;
+ if (Int32.TryParse(path.Substring(2), out num))
+ {
+ return num;
+ }
+ }
+ return -1;
+ }
+
+ void JoystickAdded(object sender, FileSystemEventArgs e)
+ {
+ lock (sync)
+ {
+ OpenJoystick(e.FullPath);
+ }
+ }
+
+ void JoystickRemoved(object sender, FileSystemEventArgs e)
+ {
+ lock (sync)
+ {
+ string file = Path.GetFileName(e.FullPath);
+ int number = GetJoystickNumber(file);
+ if (number != -1)
+ {
+ // Find which joystick id matches this number
+ int i;
+ for (i = 0; i < sticks.Count; i++)
+ {
+ if (sticks[i].Id == number)
{
- case JoystickEventType.Axis:
- // Flip vertical axes so that +1 point up.
- if (e.Number % 2 == 0)
- js.SetAxis((JoystickAxis)e.Number, e.Value / 32767.0f);
- else
- js.SetAxis((JoystickAxis)e.Number, -e.Value / 32767.0f);
- break;
-
- case JoystickEventType.Button:
- js.SetButton((JoystickButton)e.Number, e.Value != 0);
- break;
+ break;
}
}
+
+ if (i == sticks.Count)
+ {
+ Debug.Print("[Evdev] Joystick id {0} does not exist.", number);
+ }
+ else
+ {
+ CloseJoystick(sticks[i]);
+ }
}
}
}
@@ -127,51 +160,219 @@ namespace OpenTK.Platform.X11
#region Private Members
- JoystickDevice OpenJoystick(string base_path, int number)
+ Guid CreateGuid(JoystickDevice js, string path, int number)
{
- string path = base_path + number.ToString();
- JoystickDevice stick = null;
+ byte[] bytes = new byte[16];
+ for (int i = 0; i < Math.Min(bytes.Length, js.Description.Length); i++)
+ {
+ bytes[i] = (byte)js.Description[i];
+ }
+ return new Guid(bytes);
+
+#if false // Todo: move to /dev/input/event* from /dev/input/js*
+ string evdev_path = Path.Combine(Path.GetDirectoryName(path), "event" + number);
+ if (!File.Exists(evdev_path))
+ return new Guid();
+
+ int event_fd = UnsafeNativeMethods.open(evdev_path, OpenFlags.NonBlock);
+ if (event_fd < 0)
+ return new Guid();
- int fd = -1;
try
{
- fd = UnsafeNativeMethods.open(path, OpenFlags.NonBlock);
- if (fd == -1)
- return null;
+ EventInputId id;
+ if (UnsafeNativeMethods.ioctl(event_fd, EvdevInputId.Id, out id) < 0)
+ return new Guid();
- // 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;
+ int i = 0;
+ byte[] bus = BitConverter.GetBytes(id.BusType);
+ bytes[i++] = bus[0];
+ bytes[i++] = bus[1];
+ bytes[i++] = 0;
+ bytes[i++] = 0;
- // Get number of joystick axes
- int axes = 0;
- UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Axes, ref axes);
+ if (id.Vendor != 0 && id.Product != 0 && id.Version != 0)
+ {
+ byte[] vendor = BitConverter.GetBytes(id.Vendor);
+ byte[] product = BitConverter.GetBytes(id.Product);
+ byte[] version = BitConverter.GetBytes(id.Version);
+ bytes[i++] = vendor[0];
+ bytes[i++] = vendor[1];
+ bytes[i++] = 0;
+ bytes[i++] = 0;
+ bytes[i++] = product[0];
+ bytes[i++] = product[1];
+ bytes[i++] = 0;
+ bytes[i++] = 0;
+ bytes[i++] = version[0];
+ bytes[i++] = version[1];
+ bytes[i++] = 0;
+ bytes[i++] = 0;
+ }
+ else
+ {
+ for (; i < bytes.Length; i++)
+ {
+ bytes[i] = (byte)js.Description[i];
+ }
+ }
- // Get number of joystick buttons
- int buttons = 0;
- UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
-
- stick = new JoystickDevice(fd, axes, buttons);
-
- StringBuilder sb = new StringBuilder(128);
- UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Name128, sb);
- stick.Description = sb.ToString();
-
- Debug.Print("Found joystick on path {0}", path);
+ return new Guid(bytes);
}
finally
{
- if (stick == null && fd != -1)
- UnsafeNativeMethods.close(fd);
+ UnsafeNativeMethods.close(event_fd);
+ }
+#endif
+ }
+
+ JoystickDevice OpenJoystick(string path)
+ {
+ JoystickDevice stick = null;
+
+ int number = GetJoystickNumber(Path.GetFileName(path));
+ if (number >= 0)
+ {
+ 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(number, axes, buttons);
+
+ StringBuilder sb = new StringBuilder(128);
+ UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Name128, sb);
+ stick.Description = sb.ToString();
+
+ stick.Details.FileDescriptor = fd;
+ stick.Details.State.SetIsConnected(true);
+ stick.Details.Guid = CreateGuid(stick, path, number);
+
+ // Find the first disconnected joystick (if any)
+ int i;
+ for (i = 0; i < sticks.Count; i++)
+ {
+ if (!sticks[i].Details.State.IsConnected)
+ {
+ break;
+ }
+ }
+
+ // If no disconnected joystick exists, append a new slot
+ if (i == sticks.Count)
+ {
+ sticks.Add(stick);
+ }
+ else
+ {
+ sticks[i] = stick;
+ }
+
+ // Map player index to joystick
+ index_to_stick.Add(index_to_stick.Count, i);
+
+ Debug.Print("Found joystick on path {0}", path);
+ }
+ finally
+ {
+ if (stick == null && fd != -1)
+ UnsafeNativeMethods.close(fd);
+ }
}
return stick;
}
+ void CloseJoystick(JoystickDevice js)
+ {
+ UnsafeNativeMethods.close(js.Details.FileDescriptor);
+ js.Details.State = new JoystickState(); // clear joystick state
+ js.Details.FileDescriptor = -1;
+
+ // find and remove the joystick index from index_to_stick
+ int key = -1;
+ foreach (int i in index_to_stick.Keys)
+ {
+ if (sticks[index_to_stick[i]] == js)
+ {
+ key = i;
+ break;
+ }
+ }
+
+ if (index_to_stick.ContainsKey(key))
+ {
+ index_to_stick.Remove(key);
+ }
+ }
+
+ void PollJoystick(JoystickDevice js)
+ {
+ JoystickEvent e;
+
+ unsafe
+ {
+ while ((long)UnsafeNativeMethods.read(js.Details.FileDescriptor, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
+ {
+ e.Type &= ~JoystickEventType.Init;
+
+ switch (e.Type)
+ {
+ case JoystickEventType.Axis:
+ // Flip vertical axes so that +1 point up.
+ if (e.Number % 2 == 0)
+ js.Details.State.SetAxis((JoystickAxis)e.Number, e.Value);
+ else
+ js.Details.State.SetAxis((JoystickAxis)e.Number, unchecked((short)-e.Value));
+ break;
+
+ case JoystickEventType.Button:
+ js.Details.State.SetButton((JoystickButton)e.Number, e.Value != 0);
+ break;
+ }
+
+ js.Details.State.SetPacketNumber(unchecked((int)e.Time));
+ }
+ }
+ }
+
+ bool IsValid(int index)
+ {
+ return index_to_stick.ContainsKey(index);
+ }
+
#region UnsafeNativeMethods
+ struct EvdevInputId
+ {
+ public ushort BusType;
+ public ushort Vendor;
+ public ushort Product;
+ public ushort Version;
+ }
+
+ enum EvdevIoctlCode : uint
+ {
+ Id = ((byte)'E' << 8) | (0x02 << 0) //EVIOCGID, which is _IOR('E', 0x02, struct input_id)
+ }
+
+
struct JoystickEvent
{
public uint Time; // (u32) event timestamp in milliseconds
@@ -196,8 +397,8 @@ namespace OpenTK.Platform.X11
Name128 = (2u << 30) | (0x6A << 8) | (0x13 << 0) | (128 << 16) //JSIOCGNAME(128), which is _IOC(_IO_READ, 'j', 0x13, len)
}
- static readonly string JoystickPath = "/dev/input/js";
- static readonly string JoystickPathLegacy = "/dev/js";
+ static readonly string JoystickPath = "/dev/input";
+ static readonly string JoystickPathLegacy = "/dev";
[Flags]
enum OpenFlags
@@ -213,6 +414,9 @@ namespace OpenTK.Platform.X11
[DllImport("libc", SetLastError = true)]
public static extern int ioctl(int d, JoystickIoctlCode request, StringBuilder data);
+ [DllImport("libc", SetLastError = true)]
+ public static extern int ioctl(int d, EvdevIoctlCode request, out EvdevInputId data);
+
[DllImport("libc", SetLastError = true)]
public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags);
@@ -243,9 +447,9 @@ namespace OpenTK.Platform.X11
{
}
- foreach (JoystickDevice js in sticks)
+ foreach (JoystickDevice js in sticks)
{
- UnsafeNativeMethods.close(js.Id);
+ CloseJoystick(js);
}
disposed = true;
@@ -259,44 +463,39 @@ namespace OpenTK.Platform.X11
#endregion
- #region IGamePadDriver Members
-
- public GamePadCapabilities GetCapabilities(int index)
- {
- return new GamePadCapabilities();
- }
-
- public GamePadState GetState(int index)
- {
- return new GamePadState();
- }
-
- public string GetName(int index)
- {
- return String.Empty;
- }
-
- public bool SetVibration(int index, float left, float right)
- {
- return false;
- }
-
- #endregion
-
#region IJoystickDriver2 Members
JoystickState IJoystickDriver2.GetState(int index)
{
+ if (IsValid(index))
+ {
+ JoystickDevice js =
+ sticks[index_to_stick[index]];
+ PollJoystick(js);
+ return js.Details.State;
+ }
return new JoystickState();
}
JoystickCapabilities IJoystickDriver2.GetCapabilities(int index)
{
- return new JoystickCapabilities();
+ JoystickCapabilities caps = new JoystickCapabilities();
+ if (IsValid(index))
+ {
+ JoystickDevice js = sticks[index_to_stick[index]];
+ caps = new JoystickCapabilities(
+ js.Axis.Count, js.Button.Count, js.Details.State.IsConnected);
+ }
+ return caps;
}
Guid IJoystickDriver2.GetGuid(int index)
{
+ if (IsValid(index))
+ {
+ JoystickDevice js = sticks[index_to_stick[index]];
+ return js.Details.Guid;
+ }
return new Guid();
}