Merge branch 'linux_joystick' into develop

This commit is contained in:
thefiddler 2014-01-15 01:25:49 +01:00
commit e02093bb90
15 changed files with 851 additions and 404 deletions

View file

@ -78,6 +78,8 @@ namespace OpenTK
const double MaxFrequency = 500.0; // Frequency cap for Update/RenderFrame events const double MaxFrequency = 500.0; // Frequency cap for Update/RenderFrame events
readonly Stopwatch watch = new Stopwatch(); readonly Stopwatch watch = new Stopwatch();
readonly IJoystickDriver LegacyJoystick =
Factory.Default.CreateLegacyJoystickDriver();
IGraphicsContext glContext; IGraphicsContext glContext;
@ -576,9 +578,10 @@ namespace OpenTK
/// <summary> /// <summary>
/// Gets a readonly IList containing all available OpenTK.Input.JoystickDevices. /// Gets a readonly IList containing all available OpenTK.Input.JoystickDevices.
/// </summary> /// </summary>
[Obsolete("Use OpenTK.Input.Joystick and GamePad instead")]
public IList<JoystickDevice> Joysticks public IList<JoystickDevice> Joysticks
{ {
get { return InputDriver.Joysticks; } get { return LegacyJoystick.Joysticks; }
} }
#endregion #endregion

View file

@ -129,7 +129,7 @@ namespace OpenTK
/// <summary> /// <summary>
/// This property is deprecated and should not be used. /// This property is deprecated and should not be used.
/// </summary> /// </summary>
[Obsolete] [Obsolete("Use OpenTK.Input.Mouse/Keybord/Joystick/GamePad instead.")]
OpenTK.Input.IInputDriver InputDriver { get; } OpenTK.Input.IInputDriver InputDriver { get; }
/// <summary> /// <summary>

View file

@ -130,22 +130,28 @@ namespace OpenTK.Input
internal void SetAxis(JoystickAxis axis, float @value) internal void SetAxis(JoystickAxis axis, float @value)
{ {
move_args.Axis = axis; if ((int)axis < axis_collection.Count)
move_args.Delta = move_args.Value - @value; {
axis_collection[axis] = move_args.Value = @value; move_args.Axis = axis;
Move(this, move_args); 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) internal void SetButton(JoystickButton button, bool @value)
{ {
if (button_collection[button] != @value) if ((int)button < button_collection.Count)
{ {
button_args.Button = button; if (button_collection[button] != @value)
button_collection[button] = button_args.Pressed = @value; {
if (@value) button_args.Button = button;
ButtonDown(this, button_args); button_collection[button] = button_args.Pressed = @value;
else if (@value)
ButtonUp(this, button_args); ButtonDown(this, button_args);
else
ButtonUp(this, button_args);
}
} }
} }

View file

@ -166,6 +166,7 @@
<Compile Include="Platform\MappedGamePadDriver.cs" /> <Compile Include="Platform\MappedGamePadDriver.cs" />
<Compile Include="Platform\Windows\WinInputBase.cs" /> <Compile Include="Platform\Windows\WinInputBase.cs" />
<Compile Include="Platform\Windows\XInputJoystick.cs" /> <Compile Include="Platform\Windows\XInputJoystick.cs" />
<Compile Include="Platform\X11\Bindings\INotify.cs" />
<Compile Include="ToolkitOptions.cs" /> <Compile Include="ToolkitOptions.cs" />
<Compile Include="WindowBorder.cs"> <Compile Include="WindowBorder.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
@ -798,6 +799,8 @@
<Compile Include="Input\ConfigurationType.cs" /> <Compile Include="Input\ConfigurationType.cs" />
<Compile Include="Input\GamePadConfigurationSource.cs" /> <Compile Include="Input\GamePadConfigurationSource.cs" />
<Compile Include="Input\GamePadConfigurationItem.cs" /> <Compile Include="Input\GamePadConfigurationItem.cs" />
<Compile Include="Platform\LegacyJoystickDriver.cs" />
<Compile Include="Platform\PlatformFactoryBase.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>

View file

@ -33,6 +33,7 @@ using System.Text;
namespace OpenTK.Platform namespace OpenTK.Platform
{ {
using Graphics; using Graphics;
using Input;
sealed class Factory : IPlatformFactory sealed class Factory : IPlatformFactory
{ {
@ -134,27 +135,32 @@ namespace OpenTK.Platform
return default_implementation.CreateGraphicsMode(); return default_implementation.CreateGraphicsMode();
} }
public OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver() public IKeyboardDriver2 CreateKeyboardDriver()
{ {
return default_implementation.CreateKeyboardDriver(); return default_implementation.CreateKeyboardDriver();
} }
public OpenTK.Input.IMouseDriver2 CreateMouseDriver() public IMouseDriver2 CreateMouseDriver()
{ {
return default_implementation.CreateMouseDriver(); return default_implementation.CreateMouseDriver();
} }
public OpenTK.Input.IGamePadDriver CreateGamePadDriver() public IGamePadDriver CreateGamePadDriver()
{ {
return default_implementation.CreateGamePadDriver(); return default_implementation.CreateGamePadDriver();
} }
public Input.IJoystickDriver2 CreateJoystickDriver() public IJoystickDriver2 CreateJoystickDriver()
{ {
return default_implementation.CreateJoystickDriver(); return default_implementation.CreateJoystickDriver();
} }
class UnsupportedPlatform : IPlatformFactory public IJoystickDriver CreateLegacyJoystickDriver()
{
return default_implementation.CreateLegacyJoystickDriver();
}
class UnsupportedPlatform : PlatformFactoryBase
{ {
#region Fields #region Fields
@ -165,92 +171,51 @@ namespace OpenTK.Platform
#region IPlatformFactory Members #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); throw new PlatformNotSupportedException(error_string);
} }
public IDisplayDeviceDriver CreateDisplayDeviceDriver() public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{ {
throw new PlatformNotSupportedException(error_string); 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); 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); 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); throw new PlatformNotSupportedException(error_string);
} }
public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() public override IGraphicsMode CreateGraphicsMode()
{ {
throw new PlatformNotSupportedException(error_string); throw new PlatformNotSupportedException(error_string);
} }
public IGraphicsMode CreateGraphicsMode() public override IKeyboardDriver2 CreateKeyboardDriver()
{ {
throw new PlatformNotSupportedException(error_string); throw new PlatformNotSupportedException(error_string);
} }
public OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver() public override IMouseDriver2 CreateMouseDriver()
{ {
throw new PlatformNotSupportedException(error_string); throw new PlatformNotSupportedException(error_string);
} }
public OpenTK.Input.IMouseDriver2 CreateMouseDriver() public override IJoystickDriver2 CreateJoystickDriver()
{ {
throw new PlatformNotSupportedException(error_string); 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 #endregion
} }

View file

@ -54,5 +54,7 @@ namespace OpenTK.Platform
OpenTK.Input.IGamePadDriver CreateGamePadDriver(); OpenTK.Input.IGamePadDriver CreateGamePadDriver();
Input.IJoystickDriver2 CreateJoystickDriver(); Input.IJoystickDriver2 CreateJoystickDriver();
Input.IJoystickDriver CreateLegacyJoystickDriver();
} }
} }

View file

@ -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 file

@ -35,38 +35,33 @@ namespace OpenTK.Platform.MacOS
{ {
using Graphics; using Graphics;
class MacOSFactory : IPlatformFactory class MacOSFactory : PlatformFactoryBase
{ {
#region Fields
bool disposed;
readonly IInputDriver2 InputDriver = new HIDInput(); readonly IInputDriver2 InputDriver = new HIDInput();
#endregion
#region IPlatformFactory Members #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); return new CarbonGLNative(x, y, width, height, title, mode, options, device);
} }
public virtual IDisplayDeviceDriver CreateDisplayDeviceDriver() public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{ {
return new QuartzDisplayDeviceDriver(); 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); 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); return new AglContext(handle, window, shareContext);
} }
public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{ {
return (GraphicsContext.GetCurrentContextDelegate)delegate return (GraphicsContext.GetCurrentContextDelegate)delegate
{ {
@ -74,27 +69,17 @@ namespace OpenTK.Platform.MacOS
}; };
} }
public virtual IGraphicsMode CreateGraphicsMode() public override IKeyboardDriver2 CreateKeyboardDriver()
{
throw new NotSupportedException();
}
public virtual OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
{ {
return InputDriver.KeyboardDriver; return InputDriver.KeyboardDriver;
} }
public virtual OpenTK.Input.IMouseDriver2 CreateMouseDriver() public override IMouseDriver2 CreateMouseDriver()
{ {
return InputDriver.MouseDriver; return InputDriver.MouseDriver;
} }
public virtual OpenTK.Input.IGamePadDriver CreateGamePadDriver() public override IJoystickDriver2 CreateJoystickDriver()
{
return InputDriver.GamePadDriver;
}
public IJoystickDriver2 CreateJoystickDriver()
{ {
return InputDriver.JoystickDriver; return InputDriver.JoystickDriver;
} }
@ -103,33 +88,19 @@ namespace OpenTK.Platform.MacOS
#region IDisposable Members #region IDisposable Members
void Dispose(bool manual) protected override void Dispose(bool manual)
{ {
if (!disposed) if (!IsDisposed)
{ {
if (manual) if (manual)
{ {
InputDriver.Dispose(); InputDriver.Dispose();
} }
else
{ base.Dispose(manual);
Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
}
disposed = true;
} }
} }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~MacOSFactory()
{
Dispose(false);
}
#endregion #endregion
} }
} }

View file

@ -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 file

@ -32,10 +32,9 @@ using OpenTK.Input;
namespace OpenTK.Platform.SDL2 namespace OpenTK.Platform.SDL2
{ {
class Sdl2Factory : IPlatformFactory class Sdl2Factory : PlatformFactoryBase
{ {
readonly Sdl2InputDriver InputDriver = new Sdl2InputDriver(); readonly Sdl2InputDriver InputDriver = new Sdl2InputDriver();
bool disposed;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether to use SDL2 fullscreen-desktop mode /// Gets or sets a value indicating whether to use SDL2 fullscreen-desktop mode
@ -56,27 +55,27 @@ namespace OpenTK.Platform.SDL2
#region IPlatformFactory implementation #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); return new Sdl2NativeWindow(x, y, width, height, title, options, device, InputDriver);
} }
public IDisplayDeviceDriver CreateDisplayDeviceDriver() public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{ {
return new Sdl2DisplayDeviceDriver(); 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); 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(); throw new NotImplementedException();
} }
public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{ {
return (GraphicsContext.GetCurrentContextDelegate)delegate return (GraphicsContext.GetCurrentContextDelegate)delegate
{ {
@ -84,27 +83,17 @@ namespace OpenTK.Platform.SDL2
}; };
} }
public IGraphicsMode CreateGraphicsMode() public override IKeyboardDriver2 CreateKeyboardDriver()
{
return new Sdl2GraphicsMode();
}
public IKeyboardDriver2 CreateKeyboardDriver()
{ {
return InputDriver.KeyboardDriver; return InputDriver.KeyboardDriver;
} }
public IMouseDriver2 CreateMouseDriver() public override IMouseDriver2 CreateMouseDriver()
{ {
return InputDriver.MouseDriver; return InputDriver.MouseDriver;
} }
public IGamePadDriver CreateGamePadDriver() public override IJoystickDriver2 CreateJoystickDriver()
{
return InputDriver.GamePadDriver;
}
public IJoystickDriver2 CreateJoystickDriver()
{ {
return InputDriver.JoystickDriver; return InputDriver.JoystickDriver;
} }
@ -113,34 +102,19 @@ namespace OpenTK.Platform.SDL2
#region IDisposable Members #region IDisposable Members
void Dispose(bool manual) protected override void Dispose(bool manual)
{ {
if (!disposed) if (!IsDisposed)
{ {
if (manual) if (manual)
{ {
Debug.Print("Disposing {0}", GetType());
InputDriver.Dispose(); InputDriver.Dispose();
} }
else
{ base.Dispose(manual);
Debug.WriteLine("Sdl2Factory leaked, did you forget to call Dispose()?");
}
disposed = true;
} }
} }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Sdl2Factory()
{
Dispose(false);
}
#endregion #endregion
} }
} }

View file

@ -37,9 +37,8 @@ using OpenTK.Input;
namespace OpenTK.Platform.Windows namespace OpenTK.Platform.Windows
{ {
class WinFactory : IPlatformFactory class WinFactory : PlatformFactoryBase
{ {
bool disposed;
readonly object SyncRoot = new object(); readonly object SyncRoot = new object();
IInputDriver2 inputDriver; IInputDriver2 inputDriver;
@ -83,27 +82,27 @@ namespace OpenTK.Platform.Windows
#region IPlatformFactory Members #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); return new WinGLNative(x, y, width, height, title, options, device);
} }
public virtual IDisplayDeviceDriver CreateDisplayDeviceDriver() public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{ {
return new WinDisplayDeviceDriver(); 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); 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); return new WinGLContext(handle, (WinWindowInfo)window, shareContext, major, minor, flags);
} }
public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{ {
return (GraphicsContext.GetCurrentContextDelegate)delegate return (GraphicsContext.GetCurrentContextDelegate)delegate
{ {
@ -111,27 +110,22 @@ namespace OpenTK.Platform.Windows
}; };
} }
public virtual IGraphicsMode CreateGraphicsMode() public override OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
{
throw new NotSupportedException();
}
public virtual OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
{ {
return InputDriver.KeyboardDriver; return InputDriver.KeyboardDriver;
} }
public virtual OpenTK.Input.IMouseDriver2 CreateMouseDriver() public override OpenTK.Input.IMouseDriver2 CreateMouseDriver()
{ {
return InputDriver.MouseDriver; return InputDriver.MouseDriver;
} }
public virtual OpenTK.Input.IGamePadDriver CreateGamePadDriver() public override OpenTK.Input.IGamePadDriver CreateGamePadDriver()
{ {
return InputDriver.GamePadDriver; return InputDriver.GamePadDriver;
} }
public IJoystickDriver2 CreateJoystickDriver() public override IJoystickDriver2 CreateJoystickDriver()
{ {
return InputDriver.JoystickDriver; return InputDriver.JoystickDriver;
} }
@ -155,33 +149,19 @@ namespace OpenTK.Platform.Windows
#region IDisposable Members #region IDisposable Members
void Dispose(bool manual) protected override void Dispose(bool manual)
{ {
if (!disposed) if (!IsDisposed)
{ {
if (manual) if (manual)
{ {
InputDriver.Dispose(); InputDriver.Dispose();
} }
else
{ base.Dispose(manual);
Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
}
disposed = true;
} }
} }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~WinFactory()
{
Dispose(false);
}
#endregion #endregion
} }
} }

View file

@ -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 file

@ -28,10 +28,11 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
namespace OpenTK.Platform.X11 namespace OpenTK.Platform.X11
{ {
class X11Factory : IPlatformFactory class X11Factory : PlatformFactoryBase
{ {
bool disposed; bool disposed;
@ -47,27 +48,27 @@ namespace OpenTK.Platform.X11
#region IPlatformFactory Members #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); return new X11GLNative(x, y, width, height, title, mode, options, device);
} }
public virtual IDisplayDeviceDriver CreateDisplayDeviceDriver() public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{ {
return new X11DisplayDevice(); 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); 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); return new X11GLContext(handle, window, shareContext, directRendering, major, minor, flags);
} }
public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext() public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{ {
return (GraphicsContext.GetCurrentContextDelegate)delegate return (GraphicsContext.GetCurrentContextDelegate)delegate
{ {
@ -75,17 +76,17 @@ namespace OpenTK.Platform.X11
}; };
} }
public virtual IGraphicsMode CreateGraphicsMode() public override IGraphicsMode CreateGraphicsMode()
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }
public virtual OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver() public override IKeyboardDriver2 CreateKeyboardDriver()
{ {
return new X11Keyboard(); return new X11Keyboard();
} }
public virtual OpenTK.Input.IMouseDriver2 CreateMouseDriver() public override IMouseDriver2 CreateMouseDriver()
{ {
if (XI2Mouse.IsSupported(IntPtr.Zero)) if (XI2Mouse.IsSupported(IntPtr.Zero))
return new XI2Mouse(); // Requires xorg 1.7 or higher. return new XI2Mouse(); // Requires xorg 1.7 or higher.
@ -93,48 +94,11 @@ namespace OpenTK.Platform.X11
return new X11Mouse(); // Always supported. return new X11Mouse(); // Always supported.
} }
public virtual OpenTK.Input.IGamePadDriver CreateGamePadDriver() public override IJoystickDriver2 CreateJoystickDriver()
{ {
return new X11Joystick(); 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 #endregion
} }
} }

View file

@ -24,8 +24,6 @@ namespace OpenTK.Platform.X11
/// </summary> /// </summary>
internal sealed class X11Input : IInputDriver internal sealed class X11Input : IInputDriver
{ {
X11Joystick joystick_driver = new X11Joystick();
//X11WindowInfo window;
KeyboardDevice keyboard = new KeyboardDevice(); KeyboardDevice keyboard = new KeyboardDevice();
MouseDevice mouse = new MouseDevice(); MouseDevice mouse = new MouseDevice();
List<KeyboardDevice> dummy_keyboard_list = new List<KeyboardDevice>(1); List<KeyboardDevice> dummy_keyboard_list = new List<KeyboardDevice>(1);
@ -96,57 +94,6 @@ namespace OpenTK.Platform.X11
#endregion #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 #region TranslateKey
internal bool TranslateKey(ref XKeyEvent e, out Key key) internal bool TranslateKey(ref XKeyEvent e, out Key key)
@ -242,11 +189,9 @@ namespace OpenTK.Platform.X11
#endregion #endregion
#region public IList<JoystickDevice> Joysticks
public IList<JoystickDevice> Joysticks public IList<JoystickDevice> Joysticks
{ {
get { return joystick_driver.Joysticks; } get { throw new NotImplementedException(); }
} }
#endregion #endregion
@ -258,13 +203,10 @@ namespace OpenTK.Platform.X11
/// </summary> /// </summary>
public void Poll() public void Poll()
{ {
joystick_driver.Poll();
} }
#endregion #endregion
#endregion
#region --- IDisposable Members --- #region --- IDisposable Members ---
public void Dispose() public void Dispose()

View file

@ -1,4 +1,4 @@
#region License #region License
// //
// The Open Toolkit Library License // The Open Toolkit Library License
// //
@ -28,20 +28,31 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using OpenTK.Input; using OpenTK.Input;
namespace OpenTK.Platform.X11 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 #region Fields
List<JoystickDevice> sticks = new List<JoystickDevice>(); readonly object sync = new object();
IList<JoystickDevice> sticks_readonly;
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; bool disposed;
@ -51,74 +62,96 @@ namespace OpenTK.Platform.X11
public X11Joystick() public X11Joystick()
{ {
sticks_readonly = sticks.AsReadOnly(); watcher.Created += JoystickAdded;
watcher.Deleted += JoystickRemoved;
watcher.EnableRaisingEvents = true;
int number = 0, max_sticks = 25; watcher_legacy.Created += JoystickAdded;
while (number < max_sticks) watcher_legacy.Deleted += JoystickRemoved;
{ watcher_legacy.EnableRaisingEvents = true;
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);
}
}
number = 0; OpenJoysticks();
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);
}
}
} }
#endregion #endregion
#region IJoystickDriver #region Private Members
public int DeviceCount void OpenJoysticks()
{ {
get { return sticks.Count; } lock (sync)
}
public IList<JoystickDevice> Joysticks
{
get { Poll(); return sticks_readonly; }
}
public void Poll()
{
JoystickEvent e;
foreach (JoystickDevice js in sticks)
{ {
unsafe foreach (string file in Directory.GetFiles(JoystickPath))
{ {
while ((long)UnsafeNativeMethods.read(js.Id, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0) JoystickDevice<X11JoyDetails> 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<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);
}
}
}
}
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: break;
// 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;
} }
} }
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 #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(); byte[] bytes = new byte[16];
JoystickDevice<X11JoyDetails> stick = null; 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 try
{ {
fd = UnsafeNativeMethods.open(path, OpenFlags.NonBlock); EventInputId id;
if (fd == -1) if (UnsafeNativeMethods.ioctl(event_fd, EvdevInputId.Id, out id) < 0)
return null; return new Guid();
// Check joystick driver version (must be 1.0+) int i = 0;
int driver_version = 0x00000800; byte[] bus = BitConverter.GetBytes(id.BusType);
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Version, ref driver_version); bytes[i++] = bus[0];
if (driver_version < 0x00010000) bytes[i++] = bus[1];
return null; bytes[i++] = 0;
bytes[i++] = 0;
// Get number of joystick axes if (id.Vendor != 0 && id.Product != 0 && id.Version != 0)
int axes = 0; {
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Axes, ref axes); 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 return new Guid(bytes);
int buttons = 0;
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
stick = new JoystickDevice<X11JoyDetails>(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);
} }
finally finally
{ {
if (stick == null && fd != -1) UnsafeNativeMethods.close(event_fd);
UnsafeNativeMethods.close(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;
}
}
// 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; return stick;
} }
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;
}
}
if (index_to_stick.ContainsKey(key))
{
index_to_stick.Remove(key);
}
}
void PollJoystick(JoystickDevice<X11JoyDetails> 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 #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 struct JoystickEvent
{ {
public uint Time; // (u32) event timestamp in milliseconds 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) 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 JoystickPath = "/dev/input";
static readonly string JoystickPathLegacy = "/dev/js"; static readonly string JoystickPathLegacy = "/dev";
[Flags] [Flags]
enum OpenFlags enum OpenFlags
@ -213,6 +414,9 @@ namespace OpenTK.Platform.X11
[DllImport("libc", SetLastError = true)] [DllImport("libc", SetLastError = true)]
public static extern int ioctl(int d, JoystickIoctlCode request, StringBuilder data); 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)] [DllImport("libc", SetLastError = true)]
public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags); 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<X11JoyDetails> js in sticks)
{ {
UnsafeNativeMethods.close(js.Id); CloseJoystick(js);
} }
disposed = true; disposed = true;
@ -259,44 +463,39 @@ namespace OpenTK.Platform.X11
#endregion #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 #region IJoystickDriver2 Members
JoystickState IJoystickDriver2.GetState(int index) 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(); return new JoystickState();
} }
JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) 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) Guid IJoystickDriver2.GetGuid(int index)
{ {
if (IsValid(index))
{
JoystickDevice<X11JoyDetails> js = sticks[index_to_stick[index]];
return js.Details.Guid;
}
return new Guid(); return new Guid();
} }