Merge branch 'develop' of https://github.com/opentk/opentk into utf8

This commit is contained in:
Stefanos A 2014-01-16 11:44:34 +01:00
commit 606b4ddcd1
16 changed files with 916 additions and 457 deletions

118
README.md
View file

@ -1,66 +1,78 @@
OpenTK
======
The Open Toolkit is an advanced, low-level C# library that wraps OpenGL, OpenGL ES and OpenAL. It is suitable for games, scientific applications and any other project that requires 3d graphics, audio or compute functionality.
This is the official GIT repository of the project:
https://github.com/opentk/opentk
Project website: http://www.opentk.com/
Official git repository: https://github.com/opentk/opentk
Features
========
- Create cutting-edge graphics with OpenGL 4.4 and OpenGL ES 3.0.
- Integrate 3d into Windows.Forms, WPF or GTK# applications.
- Write once run everywhere: support for Windows, Mac OS X, Linux, Xamarin.Android and Xamarin.iOS.
- Use strong types and inline documentation to improve your code flow and catch errors sooner.
- Create cutting-edge graphics with OpenGL 4.4 and OpenGL ES 3.0
- Spice up your GUI with 3d graphics
- Improve your code flow with strong types and inline documentation
- Write once run everywhere!
OpenTK is available on Windows, Linux, Mac OS X, *BSD, SteamOS, Android and iOS. It can be used standalone or integrated into a GUI (Windows.Forms, WPF, GTK+, Qt, VTK, ...)
Binaries and NuGet packages available at http://www.opentk.com
Roadmap
=======
- Merge opentk/opentk (upstream) with mono/opentk (Xamarin)
- Add Portable Class Library (PCL) target
- Add multitouch API
- Add new platforms: NaCL, emscripten, Windows Metro, Ouya, Raspberry PI
- Improve OpenCL bindings
- Improve math library
Contributing
============
1. Install git and a C# IDE (see requirements section below)
2. Fork the _develop_ branch of https://github.com/opentk/opentk
3. Commit your changes in small, incremental steps with clear descriptions
4. When ready, issue a Pull Request (PR) against the _develop_ branch of https://github.com/opentk/opentk
For details on coding style and best practices, refer to https://github.com/opentk/opentk/wiki/Contributing
Requirements
============
OpenTK is designed to be used in an IDE with auto-completion and documentation tooltips:
- Visual Studio 2005 or higher
- Xamarin Studio 2.x or higher
- MonoDevelop 2.x or higher
- SharpDevelop 3.x or higher
You can develop on your favorite operating system. Compiled binaries can be deployed without recompilation on:
- Windows
- Linux
- Mac OS X
For:
- Android
- iOS
you will need to recompile your code with Xamarin (http://xamarin.com/download)
- Windows (XP/Vista/7/8), Linux, Mac OS X, *BSD, SteamOS, Android or iOS
- For graphics, OpenGL drivers or a suitable emulator, such as [ANGLE](https://github.com/opentk/opentk/tree/Dependencies/Readme.txt)
- For audio, OpenAL drivers or [OpenAL Soft](https://github.com/opentk/opentk/tree/Dependencies/Readme.txt)
- To develop desktop applications: Visual Studio, Xamarin Studio, MonoDevelop or SharpDevelop
- To develop Android applications: Xamarin Studio or the Xamarin Extensions for Visual Studio
- To develop iOS applications: Xamarin Studio and XCode
Documentation
=============
The Documentation/ folder contains extensive documentation on OpenGL, OpenGL ES and OpenAL. Start with these:
- OpenGL 4.4 API Reference.pdf
or
- OpenGL ES 3.0 API Reference.pdf
Your favorite IDE will display inline documentation for all OpenTK APIs. Tutorials can be found in the [OpenTK Manual](http://www.opentk.com/doc)
Your favorite IDE will display inline documentation for all OpenTK APIs. Additional information can be found in the [OpenTK Manual](http://www.opentk.com/doc) and in the [opentk/Documentation/](https://github.com/opentk/opentk/tree/develop/Documentation) folder.
Technical documentation about the implementation of OpenTK can be found in the [Technical Wiki](https://github.com/opentk/opentk/wiki).
Need Help?
==========
The community hangs out at the [OpenTK forums](http://www.opentk.com/forum)
If you hit a bug, post an issue on https://github.com/opentk/opentk/issues
Post your questions at the [OpenTK forums](http://www.opentk.com/forum).
Report bugs at https://github.com/opentk/opentk/issues
License
=======
The Open Toolkit is distributed under the permissive MIT/X11 license and is absolutely free.
The Open Toolkit is distributed under the permissive MIT/X11 license and is absolutely free.
http://www.opentk.com/project/license

View file

@ -78,6 +78,8 @@ namespace OpenTK
const double MaxFrequency = 500.0; // Frequency cap for Update/RenderFrame events
readonly Stopwatch watch = new Stopwatch();
readonly IJoystickDriver LegacyJoystick =
Factory.Default.CreateLegacyJoystickDriver();
IGraphicsContext glContext;
@ -576,9 +578,10 @@ namespace OpenTK
/// <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 file

@ -129,7 +129,7 @@ namespace OpenTK
/// <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 file

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

View file

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

@ -33,6 +33,7 @@ using System.Text;
namespace OpenTK.Platform
{
using Graphics;
using Input;
sealed class Factory : IPlatformFactory
{
@ -134,27 +135,32 @@ namespace OpenTK.Platform
return default_implementation.CreateGraphicsMode();
}
public OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
public IKeyboardDriver2 CreateKeyboardDriver()
{
return default_implementation.CreateKeyboardDriver();
}
public OpenTK.Input.IMouseDriver2 CreateMouseDriver()
public IMouseDriver2 CreateMouseDriver()
{
return default_implementation.CreateMouseDriver();
}
public OpenTK.Input.IGamePadDriver CreateGamePadDriver()
public IGamePadDriver CreateGamePadDriver()
{
return default_implementation.CreateGamePadDriver();
}
public Input.IJoystickDriver2 CreateJoystickDriver()
public IJoystickDriver2 CreateJoystickDriver()
{
return default_implementation.CreateJoystickDriver();
}
class UnsupportedPlatform : IPlatformFactory
public IJoystickDriver CreateLegacyJoystickDriver()
{
return default_implementation.CreateLegacyJoystickDriver();
}
class UnsupportedPlatform : PlatformFactoryBase
{
#region Fields
@ -165,92 +171,51 @@ namespace OpenTK.Platform
#region IPlatformFactory Members
public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
throw new PlatformNotSupportedException(error_string);
}
public IDisplayDeviceDriver CreateDisplayDeviceDriver()
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
throw new PlatformNotSupportedException(error_string);
}
public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new PlatformNotSupportedException(error_string);
}
public IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new PlatformNotSupportedException(error_string);
}
public IGraphicsContext CreateESContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, int major, int minor, GraphicsContextFlags flags)
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
throw new PlatformNotSupportedException(error_string);
}
public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
public override IGraphicsMode CreateGraphicsMode()
{
throw new PlatformNotSupportedException(error_string);
}
public IGraphicsMode CreateGraphicsMode()
public override IKeyboardDriver2 CreateKeyboardDriver()
{
throw new PlatformNotSupportedException(error_string);
}
public OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
public override IMouseDriver2 CreateMouseDriver()
{
throw new PlatformNotSupportedException(error_string);
}
public OpenTK.Input.IMouseDriver2 CreateMouseDriver()
public override IJoystickDriver2 CreateJoystickDriver()
{
throw new PlatformNotSupportedException(error_string);
}
public OpenTK.Input.IGamePadDriver CreateGamePadDriver()
{
throw new PlatformNotSupportedException(error_string);
}
public Input.IJoystickDriver2 CreateJoystickDriver()
{
throw new PlatformNotSupportedException(error_string);
}
#endregion
#region IDisposable Members
void Dispose(bool manual)
{
if (!disposed)
{
if (manual)
{
// nothing to do
}
else
{
Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~UnsupportedPlatform()
{
Dispose(false);
}
#endregion
}

View file

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

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
{
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 @@ namespace OpenTK.Platform.SDL2
#region IPlatformFactory implementation
public INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
return new Sdl2NativeWindow(x, y, width, height, title, options, device, InputDriver);
}
public IDisplayDeviceDriver CreateDisplayDeviceDriver()
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new Sdl2DisplayDeviceDriver();
}
virtual public IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new Sdl2GraphicsContext(mode, window, shareContext, major, minor, flags);
}
public IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
throw new NotImplementedException();
}
public GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
@ -84,27 +83,17 @@ namespace OpenTK.Platform.SDL2
};
}
public IGraphicsMode CreateGraphicsMode()
{
return new Sdl2GraphicsMode();
}
public IKeyboardDriver2 CreateKeyboardDriver()
public override IKeyboardDriver2 CreateKeyboardDriver()
{
return InputDriver.KeyboardDriver;
}
public IMouseDriver2 CreateMouseDriver()
public override IMouseDriver2 CreateMouseDriver()
{
return InputDriver.MouseDriver;
}
public IGamePadDriver CreateGamePadDriver()
{
return InputDriver.GamePadDriver;
}
public IJoystickDriver2 CreateJoystickDriver()
public override IJoystickDriver2 CreateJoystickDriver()
{
return InputDriver.JoystickDriver;
}
@ -113,34 +102,19 @@ namespace OpenTK.Platform.SDL2
#region IDisposable Members
void Dispose(bool manual)
protected override void Dispose(bool manual)
{
if (!disposed)
if (!IsDisposed)
{
if (manual)
{
Debug.Print("Disposing {0}", GetType());
InputDriver.Dispose();
}
else
{
Debug.WriteLine("Sdl2Factory leaked, did you forget to call Dispose()?");
}
disposed = true;
base.Dispose(manual);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Sdl2Factory()
{
Dispose(false);
}
#endregion
}
}

View file

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

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.Diagnostics;
using OpenTK.Graphics;
using OpenTK.Input;
namespace OpenTK.Platform.X11
{
class X11Factory : IPlatformFactory
class X11Factory : PlatformFactoryBase
{
bool disposed;
@ -47,27 +48,27 @@ namespace OpenTK.Platform.X11
#region IPlatformFactory Members
public virtual INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{
return new X11GLNative(x, y, width, height, title, mode, options, device);
}
public virtual IDisplayDeviceDriver CreateDisplayDeviceDriver()
public override IDisplayDeviceDriver CreateDisplayDeviceDriver()
{
return new X11DisplayDevice();
}
public virtual IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
public override IGraphicsContext CreateGLContext(GraphicsMode mode, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new X11GLContext(mode, window, shareContext, directRendering, major, minor, flags);
}
public virtual IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
public override IGraphicsContext CreateGLContext(ContextHandle handle, IWindowInfo window, IGraphicsContext shareContext, bool directRendering, int major, int minor, GraphicsContextFlags flags)
{
return new X11GLContext(handle, window, shareContext, directRendering, major, minor, flags);
}
public virtual GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
public override GraphicsContext.GetCurrentContextDelegate CreateGetCurrentGraphicsContext()
{
return (GraphicsContext.GetCurrentContextDelegate)delegate
{
@ -75,17 +76,17 @@ namespace OpenTK.Platform.X11
};
}
public virtual IGraphicsMode CreateGraphicsMode()
public override IGraphicsMode CreateGraphicsMode()
{
throw new NotSupportedException();
}
public virtual OpenTK.Input.IKeyboardDriver2 CreateKeyboardDriver()
public override IKeyboardDriver2 CreateKeyboardDriver()
{
return new X11Keyboard();
}
public virtual OpenTK.Input.IMouseDriver2 CreateMouseDriver()
public override IMouseDriver2 CreateMouseDriver()
{
if (XI2Mouse.IsSupported(IntPtr.Zero))
return new XI2Mouse(); // Requires xorg 1.7 or higher.
@ -93,48 +94,11 @@ namespace OpenTK.Platform.X11
return new X11Mouse(); // Always supported.
}
public virtual OpenTK.Input.IGamePadDriver CreateGamePadDriver()
public override IJoystickDriver2 CreateJoystickDriver()
{
return new X11Joystick();
}
public virtual OpenTK.Input.IJoystickDriver2 CreateJoystickDriver()
{
return new X11Joystick();
}
#endregion
#region IDisposable Members
void Dispose(bool manual)
{
if (!disposed)
{
if (manual)
{
// nothing to do
}
else
{
Debug.Print("{0} leaked, did you forget to call Dispose()?", GetType());
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~X11Factory()
{
Dispose(false);
}
#endregion
}
}

View file

@ -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 @@ namespace OpenTK.Platform.X11
#endregion
#region private void InternalPoll()
#if false
private void InternalPoll()
{
X11.XEvent e = new XEvent();
try
{
while (!disposed)
{
Functions.XMaskEvent(window.Display,
EventMask.PointerMotionMask | EventMask.PointerMotionHintMask |
EventMask.ButtonPressMask | EventMask.ButtonReleaseMask |
EventMask.KeyPressMask | EventMask.KeyReleaseMask |
EventMask.StructureNotifyMask, ref e);
if (disposed)
return;
switch (e.type)
{
case XEventName.KeyPress:
case XEventName.KeyRelease:
keyboardDriver.ProcessKeyboardEvent(ref e.KeyEvent);
break;
case XEventName.ButtonPress:
case XEventName.ButtonRelease:
mouseDriver.ProcessButton(ref e.ButtonEvent);
break;
case XEventName.MotionNotify:
mouseDriver.ProcessMotion(ref e.MotionEvent);
break;
case XEventName.DestroyNotify:
Functions.XPutBackEvent(window.Display, ref e);
Functions.XAutoRepeatOn(window.Display);
return;
}
}
}
catch (ThreadAbortException expt)
{
Functions.XUnmapWindow(window.Display, window.Handle);
Functions.XDestroyWindow(window.Display, window.Handle);
return;
}
}
#endif
#endregion
#region TranslateKey
internal bool TranslateKey(ref XKeyEvent e, out Key key)
@ -242,11 +189,9 @@ namespace OpenTK.Platform.X11
#endregion
#region public IList<JoystickDevice> Joysticks
public IList<JoystickDevice> Joysticks
{
get { return joystick_driver.Joysticks; }
get { throw new NotImplementedException(); }
}
#endregion
@ -258,13 +203,10 @@ namespace OpenTK.Platform.X11
/// </summary>
public void Poll()
{
joystick_driver.Poll();
}
#endregion
#endregion
#region --- IDisposable Members ---
public void Dispose()

View file

@ -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 @@ namespace OpenTK.Platform.X11
public X11Joystick()
{
sticks_readonly = sticks.AsReadOnly();
watcher.Created += JoystickAdded;
watcher.Deleted += JoystickRemoved;
watcher.EnableRaisingEvents = true;
int number = 0, max_sticks = 25;
while (number < max_sticks)
{
JoystickDevice stick = OpenJoystick(JoystickPath, number++);
if (stick != null)
{
//stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
//number, stick.Axis.Count, stick.Button.Count, JoystickPath);
sticks.Add(stick);
}
}
watcher_legacy.Created += JoystickAdded;
watcher_legacy.Deleted += JoystickRemoved;
watcher_legacy.EnableRaisingEvents = true;
number = 0;
while (number < max_sticks)
{
JoystickDevice stick = OpenJoystick(JoystickPathLegacy, number++);
if (stick != null)
{
//stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
//number, stick.Axis.Count, stick.Button.Count, JoystickPathLegacy);
sticks.Add(stick);
}
}
OpenJoysticks();
}
#endregion
#region IJoystickDriver
#region Private Members
public int DeviceCount
void OpenJoysticks()
{
get { return sticks.Count; }
}
public IList<JoystickDevice> Joysticks
{
get { Poll(); return sticks_readonly; }
}
public void Poll()
{
JoystickEvent e;
foreach (JoystickDevice js in sticks)
lock (sync)
{
unsafe
foreach (string file in Directory.GetFiles(JoystickPath))
{
while ((long)UnsafeNativeMethods.read(js.Id, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
JoystickDevice<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:
// Flip vertical axes so that +1 point up.
if (e.Number % 2 == 0)
js.SetAxis((JoystickAxis)e.Number, e.Value / 32767.0f);
else
js.SetAxis((JoystickAxis)e.Number, -e.Value / 32767.0f);
break;
case JoystickEventType.Button:
js.SetButton((JoystickButton)e.Number, e.Value != 0);
break;
break;
}
}
if (i == sticks.Count)
{
Debug.Print("[Evdev] Joystick id {0} does not exist.", number);
}
else
{
CloseJoystick(sticks[i]);
}
}
}
}
@ -127,51 +160,219 @@ namespace OpenTK.Platform.X11
#region Private Members
JoystickDevice<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();
// Check joystick driver version (must be 1.0+)
int driver_version = 0x00000800;
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Version, ref driver_version);
if (driver_version < 0x00010000)
return null;
int i = 0;
byte[] bus = BitConverter.GetBytes(id.BusType);
bytes[i++] = bus[0];
bytes[i++] = bus[1];
bytes[i++] = 0;
bytes[i++] = 0;
// Get number of joystick axes
int axes = 0;
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Axes, ref axes);
if (id.Vendor != 0 && id.Product != 0 && id.Version != 0)
{
byte[] vendor = BitConverter.GetBytes(id.Vendor);
byte[] product = BitConverter.GetBytes(id.Product);
byte[] version = BitConverter.GetBytes(id.Version);
bytes[i++] = vendor[0];
bytes[i++] = vendor[1];
bytes[i++] = 0;
bytes[i++] = 0;
bytes[i++] = product[0];
bytes[i++] = product[1];
bytes[i++] = 0;
bytes[i++] = 0;
bytes[i++] = version[0];
bytes[i++] = version[1];
bytes[i++] = 0;
bytes[i++] = 0;
}
else
{
for (; i < bytes.Length; i++)
{
bytes[i] = (byte)js.Description[i];
}
}
// Get number of joystick buttons
int buttons = 0;
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
stick = new JoystickDevice<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);
return new Guid(bytes);
}
finally
{
if (stick == null && fd != -1)
UnsafeNativeMethods.close(fd);
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;
}
}
// If no disconnected joystick exists, append a new slot
if (i == sticks.Count)
{
sticks.Add(stick);
}
else
{
sticks[i] = stick;
}
// Map player index to joystick
index_to_stick.Add(index_to_stick.Count, i);
Debug.Print("Found joystick on path {0}", path);
}
finally
{
if (stick == null && fd != -1)
UnsafeNativeMethods.close(fd);
}
}
return stick;
}
void CloseJoystick(JoystickDevice<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
struct EvdevInputId
{
public ushort BusType;
public ushort Vendor;
public ushort Product;
public ushort Version;
}
enum EvdevIoctlCode : uint
{
Id = ((byte)'E' << 8) | (0x02 << 0) //EVIOCGID, which is _IOR('E', 0x02, struct input_id)
}
struct JoystickEvent
{
public uint Time; // (u32) event timestamp in milliseconds
@ -196,8 +397,8 @@ namespace OpenTK.Platform.X11
Name128 = (2u << 30) | (0x6A << 8) | (0x13 << 0) | (128 << 16) //JSIOCGNAME(128), which is _IOC(_IO_READ, 'j', 0x13, len)
}
static readonly string JoystickPath = "/dev/input/js";
static readonly string JoystickPathLegacy = "/dev/js";
static readonly string JoystickPath = "/dev/input";
static readonly string JoystickPathLegacy = "/dev";
[Flags]
enum OpenFlags
@ -213,6 +414,9 @@ namespace OpenTK.Platform.X11
[DllImport("libc", SetLastError = true)]
public static extern int ioctl(int d, JoystickIoctlCode request, StringBuilder data);
[DllImport("libc", SetLastError = true)]
public static extern int ioctl(int d, EvdevIoctlCode request, out EvdevInputId data);
[DllImport("libc", SetLastError = true)]
public static extern int open([MarshalAs(UnmanagedType.LPStr)]string pathname, OpenFlags flags);
@ -243,9 +447,9 @@ namespace OpenTK.Platform.X11
{
}
foreach (JoystickDevice js in sticks)
foreach (JoystickDevice<X11JoyDetails> js in sticks)
{
UnsafeNativeMethods.close(js.Id);
CloseJoystick(js);
}
disposed = true;
@ -259,44 +463,39 @@ namespace OpenTK.Platform.X11
#endregion
#region IGamePadDriver Members
public GamePadCapabilities GetCapabilities(int index)
{
return new GamePadCapabilities();
}
public GamePadState GetState(int index)
{
return new GamePadState();
}
public string GetName(int index)
{
return String.Empty;
}
public bool SetVibration(int index, float left, float right)
{
return false;
}
#endregion
#region IJoystickDriver2 Members
JoystickState IJoystickDriver2.GetState(int index)
{
if (IsValid(index))
{
JoystickDevice<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();
}