Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'linux_joystick' into develop

  • Loading branch information...
commit e02093bb905e734942d0fa9a212088cc00b1e0eb 2 parents 962a9f7 + 44e2576
@thefiddler thefiddler authored
View
5 Source/OpenTK/GameWindow.cs
@@ -78,6 +78,8 @@ public class GameWindow : NativeWindow, IGameWindow, IDisposable
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 @@ public bool IsExiting
/// <summary>
/// Gets a readonly IList containing all available OpenTK.Input.JoystickDevices.
/// </summary>
+ [Obsolete("Use OpenTK.Input.Joystick and GamePad instead")]
public IList<JoystickDevice> Joysticks
{
- get { return InputDriver.Joysticks; }
+ get { return LegacyJoystick.Joysticks; }
}
#endregion
View
2  Source/OpenTK/INativeWindow.cs
@@ -129,7 +129,7 @@ public interface INativeWindow : IDisposable
/// <summary>
/// This property is deprecated and should not be used.
/// </summary>
- [Obsolete]
+ [Obsolete("Use OpenTK.Input.Mouse/Keybord/Joystick/GamePad instead.")]
OpenTK.Input.IInputDriver InputDriver { get; }
/// <summary>
View
28 Source/OpenTK/Input/JoystickDevice.cs
@@ -130,22 +130,28 @@ internal int Id
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);
+ }
}
}
View
3  Source/OpenTK/OpenTK.csproj
@@ -166,6 +166,7 @@
<Compile Include="Platform\MappedGamePadDriver.cs" />
<Compile Include="Platform\Windows\WinInputBase.cs" />
<Compile Include="Platform\Windows\XInputJoystick.cs" />
+ <Compile Include="Platform\X11\Bindings\INotify.cs" />
<Compile Include="ToolkitOptions.cs" />
<Compile Include="WindowBorder.cs">
<SubType>Code</SubType>
@@ -798,6 +799,8 @@
<Compile Include="Input\ConfigurationType.cs" />
<Compile Include="Input\GamePadConfigurationSource.cs" />
<Compile Include="Input\GamePadConfigurationItem.cs" />
+ <Compile Include="Platform\LegacyJoystickDriver.cs" />
+ <Compile Include="Platform\PlatformFactoryBase.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
View
75 Source/OpenTK/Platform/Factory.cs
@@ -33,6 +33,7 @@
namespace OpenTK.Platform
{
using Graphics;
+ using Input;
sealed class Factory : IPlatformFactory
{
@@ -134,27 +135,32 @@ public IGraphicsMode CreateGraphicsMode()
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 @@ class UnsupportedPlatform : IPlatformFactory
#region IPlatformFactory Members
- public 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 INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
throw new PlatformNotSupportedException(error_string);
}
- public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
+ public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
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(GraphicsMode mode, 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 IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new PlatformNotSupportedException(error_string);
}
- public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
+ public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
throw new PlatformNotSupportedException(error_string);
}
- public IGraphicsMode CreateGraphicsMode()
+ public override IGraphicsMode CreateGraphicsMode()
{
throw new PlatformNotSupportedException(error_string);
}
- public OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
+ public override IKeyboardDriver2 CreateKeyboardDriver()
{
throw new PlatformNotSupportedException(error_string);
}
- public OpenTK.Input.IMouseDriver2 CreateMouseDriver()
+ public override IMouseDriver2 CreateMouseDriver()
{
throw new PlatformNotSupportedException(error_string);
}
- public OpenTK.Input.IGamePadDriver CreateGamePadDriver()
+ public override IJoystickDriver2 CreateJoystickDriver()
{
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
}
View
2  Source/OpenTK/Platform/IPlatformFactory.cs
@@ -54,5 +54,7 @@ interface IPlatformFactory : IDisposable
OpenTK.Input.IGamePadDriver CreateGamePadDriver();
Input.IJoystickDriver2 CreateJoystickDriver();
+
+ Input.IJoystickDriver CreateLegacyJoystickDriver();
}
}
View
108 Source/OpenTK/Platform/LegacyJoystickDriver.cs
@@ -0,0 +1,108 @@
+#region License
+//
+// LegacyJoystickDriver.cs
+//
+// Author:
+// Stefanos A. <stapostol@gmail.com>
+//
+// 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<JoystickDevice> joysticks = new List<JoystickDevice>();
+ readonly IList<JoystickDevice> 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<JoystickDevice> Joysticks
+ {
+ get
+ {
+ Poll();
+ return joysticks_readonly;
+ }
+ }
+
+ #endregion
+ }
+}
+
View
55 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 @@ public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphic
};
}
- 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,31 +88,17 @@ public IJoystickDriver2 CreateJoystickDriver()
#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;
- }
- }
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~MacOSFactory()
- {
- Dispose(false);
+ base.Dispose(manual);
+ }
}
#endregion
View
120 Source/OpenTK/Platform/PlatformFactoryBase.cs
@@ -0,0 +1,120 @@
+#region License
+//
+// PlatformFactoryBase.cs
+//
+// Author:
+// Stefanos A. <stapostol@gmail.com>
+//
+// 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
+ /// <summary>
+ /// Implements IPlatformFactory functionality that is common
+ /// for all platform backends. IPlatformFactory implementations
+ /// should inherit from this class.
+ /// </summary>
+ 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
+ }
+}
+
View
52 Source/OpenTK/Platform/SDL2/Sdl2Factory.cs
@@ -32,10 +32,9 @@
namespace OpenTK.Platform.SDL2
{
- class Sdl2Factory : IPlatformFactory
+ class Sdl2Factory : PlatformFactoryBase
{
readonly Sdl2InputDriver InputDriver = new Sdl2InputDriver();
- bool disposed;
/// <summary>
/// Gets or sets a value indicating whether to use SDL2 fullscreen-desktop mode
@@ -56,27 +55,27 @@ public Sdl2Factory()
#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 @@ public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext
};
}
- 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,32 +102,17 @@ public IJoystickDriver2 CreateJoystickDriver()
#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;
- }
- }
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- ~Sdl2Factory()
- {
- Dispose(false);
+ base.Dispose(manual);
+ }
}
#endregion
View
48 Source/OpenTK/Platform/Windows/WinFactory.cs
@@ -37,9 +37,8 @@
namespace OpenTK.Platform.Windows
{
- class WinFactory : IPlatformFactory
+ class WinFactory : PlatformFactoryBase
{
- bool disposed;
readonly object SyncRoot = new object();
IInputDriver2 inputDriver;
@@ -83,27 +82,27 @@ static void LoadOpenGL()
#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 @@ public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphic
};
}
- 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,31 +149,17 @@ IInputDriver2 InputDriver
#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;
- }
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- ~WinFactory()
- {
- Dispose(false);
+ base.Dispose(manual);
+ }
}
#endregion
View
210 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 = "";
+
+ /// <summary>
+ /// Create and initialize inotify instance
+ /// </summary>
+ /// <returns></returns>
+ [DllImport(lib, EntryPoint = "inotify_init", ExactSpelling = true)]
+ public static extern int Init();
+
+ /// <summary>
+ /// Create and initialize inotify instance with specified flags
+ /// </summary>
+ /// <param name="flags">See <see cref="INotifyInitFlags"/></param>
+ /// <returns>A <c>System.Int32</c> handle to a inotify instance</returns>
+ [DllImport(lib, EntryPoint = "inotify_init1", ExactSpelling = true)]
+ public static extern int Init(INotifyFlags flags);
+
+ /// <summary>
+ /// Add watch of object pathname to inotify instance fd. Notify about
+ /// events specified by mask
+ /// </summary>
+ [DllImport(lib, EntryPoint = "inotify_add_watch", ExactSpelling = true)]
+ public static extern int AddWatch(int fd, string pathname, INotifyFlags mask);
+
+ /// <summary>
+ /// Remove the watch specified by wd from the inotify instance fd
+ /// </summary>
+ [DllImport(lib, EntryPoint = "inotify_rm_watch", ExactSpelling = true)]
+ public static extern int RemoveWatch(int fd, int wd);
+ }
+
+ /// <summary>
+ /// Describes an INotify event
+ /// </summary>
+ struct INotifyEvent
+ {
+ /// <summary>
+ /// Watch descriptor for wd parameter of INotify methods
+ /// </summary>
+ public int WatchDescriptor;
+
+ /// <summary>
+ /// Watch mask for mask parameter of INotify methods
+ /// </summary>
+ public INotifyFlags WatchMask;
+
+ /// <summary>
+ /// Cookie to synchronize two events
+ /// </summary>
+ public uint Cookie;
+
+ /// <summary>
+ /// Length (including NULs) of name
+ /// </summary>
+ public uint Length;
+
+ /// <summary>
+ ///
+ /// </summary>
+ public IntPtr Name;
+ }
+
+ /// <summary>
+ /// Flags for the parameter of <see cref="INotify.Init(INotifyFlags)"/>
+ /// </summary>
+ [Flags]
+ enum INotifyInitFlags
+ {
+ CloExec = 02000000,
+ NonBlock = 04000
+ }
+
+ /// \internal
+ /// <summary>
+ /// Supported events suitable for MASK parameter of AddWatch.
+ /// </summary>
+ [Flags]
+ enum INotifyFlags
+ {
+ /// <summary>
+ /// File was accessed
+ /// </summary>
+ Access = 0x00000001,
+
+ /// <summary>
+ /// File was modified
+ /// </summary>
+ Modify = 0x00000002,
+
+ /// <summary>
+ /// Metadata changed
+ /// </summary>
+ Attrib = 0x00000004,
+
+ /// <summary>
+ /// Writable file was closed
+ /// </summary>
+ CloseWrite = 0x00000008,
+
+ /// <summary>
+ /// Unwritable file closed
+ /// </summary>
+ CloseNoWrite = 0x00000010,
+
+ /// <summary>
+ /// File closed
+ /// </summary>
+ Close = CloseWrite | CloseNoWrite,
+
+ /// <summary>
+ /// File was opened
+ /// </summary>
+ Open = 0x00000020,
+
+ /// <summary>
+ /// File was moved from X
+ /// </summary>
+ MovedFrom = 0x00000040,
+
+ /// <summary>
+ /// File was moved to Y
+ /// </summary>
+ MovedTo = 0x00000080,
+
+ /// <summary>
+ /// File was moved
+ /// </summary>
+ Move = MovedFrom | MovedTo,
+
+ /// <summary>
+ /// Subfile was created
+ /// </summary>
+ Create = 0x00000100,
+
+ /// <summary>
+ /// Subfile was deleted
+ /// </summary>
+ Delete = 0x00000200,
+
+ /// <summary>
+ /// Self was deleted
+ /// </summary>
+ DeleteSelf = 0x00000400,
+
+ /// <summary>
+ /// Self was moved
+ /// </summary>
+ MoveSelf = 0x00000800,
+
+ /// <summary>
+ /// Backing fs was unmounted
+ /// </summary>
+ Unmount = 0x00002000,
+
+ /// <summary>
+ /// Event queue overflowed
+ /// </summary>
+ QueueOverflow = 0x00004000,
+
+ /// <summary>
+ /// File was ignored
+ /// </summary>
+ Ignored = 0x00008000,
+
+ /// <summary>
+ /// Only watch the path if it is a directory
+ /// </summary>
+ OnlyDirectory = 0x01000000,
+
+ /// <summary>
+ /// Do not follow symlinks
+ /// </summary>
+ DontFollow = 0x02000000,
+
+ /// <summary>
+ /// Add to the mask of an already existing watch
+ /// </summary>
+ MaskAdd = 0x20000000,
+
+ /// <summary>
+ /// Event occurred against dir
+ /// </summary>
+ IsDirectory = 0x40000000,
+
+ /// <summary>
+ /// Only send event once
+ /// </summary>
+ Oneshot = 0x80000000,
+
+ /// <summary>
+ /// All events which a program can wait on
+ /// </summary>
+ AllEvents =
+ Access | Modify | Attrib | Close | Open | Move |
+ Create | Delete | DeleteSelf | MoveSelf
+ }
+#endif
+}
View
58 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 @@ public X11Factory()
#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 @@ public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphic
};
}
- 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 @@ public virtual OpenTK.Input.IMouseDriver2 CreateMouseDriver()
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
}
}
View
60 Source/OpenTK/Platform/X11/X11Input.cs
@@ -24,8 +24,6 @@ namespace OpenTK.Platform.X11
/// </summary>
internal sealed class X11Input : IInputDriver
{
- X11Joystick joystick_driver = new X11Joystick();
- //X11WindowInfo window;
KeyboardDevice keyboard = new KeyboardDevice();
MouseDevice mouse = new MouseDevice();
List<KeyboardDevice> dummy_keyboard_list = new List<KeyboardDevice>(1);
@@ -96,57 +94,6 @@ public X11Input(IWindowInfo attach)
#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 @@ public IList<MouseDevice> Mouse
#endregion
- #region public IList<JoystickDevice> Joysticks
-
public IList<JoystickDevice> Joysticks
{
- get { return joystick_driver.Joysticks; }
+ get { throw new NotImplementedException(); }
}
#endregion
@@ -258,13 +203,10 @@ public IList<JoystickDevice> Joysticks
/// </summary>
public void Poll()
{
- joystick_driver.Poll();
}
#endregion
- #endregion
-
#region --- IDisposable Members ---
public void Dispose()
View
407 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<JoystickDevice> sticks = new List<JoystickDevice>();
- IList<JoystickDevice> sticks_readonly;
+ readonly object sync = new object();
+
+ readonly FileSystemWatcher watcher = new FileSystemWatcher(JoystickPath);
+ readonly FileSystemWatcher watcher_legacy = new FileSystemWatcher(JoystickPathLegacy);
+
+ readonly Dictionary<int, int> index_to_stick = new Dictionary<int, int>();
+ List<JoystickDevice<X11JoyDetails>> sticks = new List<JoystickDevice<X11JoyDetails>>();
bool disposed;
@@ -51,74 +62,96 @@ sealed class X11Joystick : IJoystickDriver, IJoystickDriver2, IGamePadDriver
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)
+ watcher_legacy.Created += JoystickAdded;
+ watcher_legacy.Deleted += JoystickRemoved;
+ watcher_legacy.EnableRaisingEvents = true;
+
+ OpenJoysticks();
+ }
+
+ #endregion
+
+ #region Private Members
+
+ void OpenJoysticks()
+ {
+ lock (sync)
{
- JoystickDevice stick = OpenJoystick(JoystickPath, number++);
- if (stick != null)
+ foreach (string file in Directory.GetFiles(JoystickPath))
{
- //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
+ JoystickDevice<X11JoyDetails> 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, JoystickPath);
- sticks.Add(stick);
+ sticks.Add(stick);
+ }
}
- }
- number = 0;
- while (number < max_sticks)
- {
- JoystickDevice stick = OpenJoystick(JoystickPathLegacy, number++);
- if (stick != null)
+ foreach (string file in Directory.GetFiles(JoystickPathLegacy))
{
- //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
+ JoystickDevice<X11JoyDetails> 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);
+ sticks.Add(stick);
+ }
}
}
}
- #endregion
-
- #region IJoystickDriver
-
- public int DeviceCount
+ int GetJoystickNumber(string path)
{
- get { return sticks.Count; }
+ if (path.StartsWith("js"))
+ {
+ int num;
+ if (Int32.TryParse(path.Substring(2), out num))
+ {
+ return num;
+ }
+ }
+ return -1;
}
- public IList<JoystickDevice> Joysticks
+ void JoystickAdded(object sender, FileSystemEventArgs e)
{
- get { Poll(); return sticks_readonly; }
+ lock (sync)
+ {
+ OpenJoystick(e.FullPath);
+ }
}
- public void Poll()
+ void JoystickRemoved(object sender, FileSystemEventArgs e)
{
- JoystickEvent e;
-
- foreach (JoystickDevice js in sticks)
+ lock (sync)
{
- unsafe
+ string file = Path.GetFileName(e.FullPath);
+ int number = GetJoystickNumber(file);
+ if (number != -1)
{
- while ((long)UnsafeNativeMethods.read(js.Id, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
+ // Find which joystick id matches this number
+ int i;
+ for (i = 0; i < sticks.Count; i++)
{
- e.Type &= ~JoystickEventType.Init;
-
- switch (e.Type)
+ 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 @@ public void Poll()
#region Private Members
- JoystickDevice<X11JoyDetails> OpenJoystick(string base_path, int number)
+ Guid CreateGuid(JoystickDevice<X11JoyDetails> js, string path, int number)
{
- string path = base_path + number.ToString();
- JoystickDevice<X11JoyDetails> 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();
+
+ int i = 0;
+ byte[] bus = BitConverter.GetBytes(id.BusType);
+ bytes[i++] = bus[0];
+ bytes[i++] = bus[1];
+ bytes[i++] = 0;
+ bytes[i++] = 0;
+
+ 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];
+ }
+ }
+
+ return new Guid(bytes);
+ }
+ finally
+ {
+ UnsafeNativeMethods.close(event_fd);
+ }
+#endif
+ }
+
+ JoystickDevice<X11JoyDetails> OpenJoystick(string path)
+ {
+ JoystickDevice<X11JoyDetails> 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<X11JoyDetails>(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;
+ }
+ }
- // 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;
+ // If no disconnected joystick exists, append a new slot
+ if (i == sticks.Count)
+ {
+ sticks.Add(stick);
+ }
+ else
+ {
+ sticks[i] = stick;
+ }
- // Get number of joystick axes
- int axes = 0;
- UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Axes, ref axes);
+ // Map player index to joystick
+ index_to_stick.Add(index_to_stick.Count, i);
- // Get number of joystick buttons
- int buttons = 0;
- UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
+ Debug.Print("Found joystick on path {0}", path);
+ }
+ finally
+ {
+ if (stick == null && fd != -1)
+ UnsafeNativeMethods.close(fd);
+ }
+ }
- stick = new JoystickDevice<X11JoyDetails>(fd, axes, buttons);
+ return stick;
+ }
- StringBuilder sb = new StringBuilder(128);
- UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Name128, sb);
- stick.Description = sb.ToString();
+ void CloseJoystick(JoystickDevice<X11JoyDetails> 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;
+ }
+ }
- Debug.Print("Found joystick on path {0}", path);
+ if (index_to_stick.ContainsKey(key))
+ {
+ index_to_stick.Remove(key);
}
- finally
+ }
+
+ void PollJoystick(JoystickDevice<X11JoyDetails> js)
+ {
+ JoystickEvent e;
+
+ unsafe
{
- if (stick == null && fd != -1)
- UnsafeNativeMethods.close(fd);
+ 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));
+ }
}
+ }
- return stick;
+ 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 @@ enum JoystickIoctlCode : uint
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
@@ -214,6 +415,9 @@ static class UnsafeNativeMethods
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);
[DllImport("libc", SetLastError = true)]
@@ -243,9 +447,9 @@ void Dispose(bool manual)
{
}
- foreach (JoystickDevice js in sticks)
+ foreach (JoystickDevice<X11JoyDetails> js in sticks)
{
- UnsafeNativeMethods.close(js.Id);
+ CloseJoystick(js);
}
disposed = true;
@@ -259,44 +463,39 @@ void Dispose(bool manual)
#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<X11JoyDetails> 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<X11JoyDetails> 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<X11JoyDetails> js = sticks[index_to_stick[index]];
+ return js.Details.Guid;
+ }
return new Guid();
}
Please sign in to comment.
Something went wrong with that request. Please try again.