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

@ -129,14 +129,19 @@ namespace OpenTK.Input
}
internal void SetAxis(JoystickAxis axis, float @value)
{
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 ((int)button < button_collection.Count)
{
if (button_collection[button] != @value)
{
@ -148,6 +153,7 @@ namespace OpenTK.Input
ButtonUp(this, button_args);
}
}
}
#endregion
}

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,31 +88,17 @@ 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;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
base.Dispose(manual);
}
~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,32 +102,17 @@ 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;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
base.Dispose(manual);
}
~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,31 +149,17 @@ 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;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
base.Dispose(manual);
}
~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,12 +62,28 @@ 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)
watcher_legacy.Created += JoystickAdded;
watcher_legacy.Deleted += JoystickRemoved;
watcher_legacy.EnableRaisingEvents = true;
OpenJoysticks();
}
#endregion
#region Private Members
void OpenJoysticks()
{
JoystickDevice stick = OpenJoystick(JoystickPath, number++);
lock (sync)
{
foreach (string file in Directory.GetFiles(JoystickPath))
{
JoystickDevice<X11JoyDetails> stick = OpenJoystick(file);
if (stick != null)
{
//stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
@ -65,10 +92,9 @@ namespace OpenTK.Platform.X11
}
}
number = 0;
while (number < max_sticks)
foreach (string file in Directory.GetFiles(JoystickPathLegacy))
{
JoystickDevice stick = OpenJoystick(JoystickPathLegacy, number++);
JoystickDevice<X11JoyDetails> stick = OpenJoystick(file);
if (stick != null)
{
//stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})",
@ -77,47 +103,54 @@ namespace OpenTK.Platform.X11
}
}
}
#endregion
#region IJoystickDriver
public int DeviceCount
{
get { return sticks.Count; }
}
public IList<JoystickDevice> Joysticks
int GetJoystickNumber(string path)
{
get { Poll(); return sticks_readonly; }
if (path.StartsWith("js"))
{
int num;
if (Int32.TryParse(path.Substring(2), out num))
{
return num;
}
}
return -1;
}
public void Poll()
void JoystickAdded(object sender, FileSystemEventArgs e)
{
JoystickEvent e;
lock (sync)
{
OpenJoystick(e.FullPath);
}
}
foreach (JoystickDevice js in sticks)
void JoystickRemoved(object sender, FileSystemEventArgs e)
{
unsafe
lock (sync)
{
while ((long)UnsafeNativeMethods.read(js.Id, (void*)&e, (UIntPtr)sizeof(JoystickEvent)) > 0)
string file = Path.GetFileName(e.FullPath);
int number = GetJoystickNumber(file);
if (number != -1)
{
e.Type &= ~JoystickEventType.Init;
// Find which joystick id matches this number
int i;
for (i = 0; i < sticks.Count; i++)
{
if (sticks[i].Id == number)
{
break;
}
}
switch (e.Type)
if (i == sticks.Count)
{
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);
Debug.Print("[Evdev] Joystick id {0} does not exist.", number);
}
else
js.SetAxis((JoystickAxis)e.Number, -e.Value / 32767.0f);
break;
case JoystickEventType.Button:
js.SetButton((JoystickButton)e.Number, e.Value != 0);
break;
}
{
CloseJoystick(sticks[i]);
}
}
}
@ -127,11 +160,79 @@ namespace OpenTK.Platform.X11
#region Private Members
JoystickDevice<X11JoyDetails> OpenJoystick(string base_path, int number)
Guid CreateGuid(JoystickDevice<X11JoyDetails> js, string path, int number)
{
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();
try
{
EventInputId id;
if (UnsafeNativeMethods.ioctl(event_fd, EvdevInputId.Id, out id) < 0)
return new Guid();
int i = 0;
byte[] bus = BitConverter.GetBytes(id.BusType);
bytes[i++] = bus[0];
bytes[i++] = bus[1];
bytes[i++] = 0;
bytes[i++] = 0;
if (id.Vendor != 0 && id.Product != 0 && id.Version != 0)
{
byte[] vendor = BitConverter.GetBytes(id.Vendor);
byte[] product = BitConverter.GetBytes(id.Product);
byte[] version = BitConverter.GetBytes(id.Version);
bytes[i++] = vendor[0];
bytes[i++] = vendor[1];
bytes[i++] = 0;
bytes[i++] = 0;
bytes[i++] = product[0];
bytes[i++] = product[1];
bytes[i++] = 0;
bytes[i++] = 0;
bytes[i++] = version[0];
bytes[i++] = version[1];
bytes[i++] = 0;
bytes[i++] = 0;
}
else
{
for (; i < bytes.Length; i++)
{
bytes[i] = (byte)js.Description[i];
}
}
return new Guid(bytes);
}
finally
{
UnsafeNativeMethods.close(event_fd);
}
#endif
}
JoystickDevice<X11JoyDetails> OpenJoystick(string path)
{
string path = base_path + number.ToString();
JoystickDevice<X11JoyDetails> stick = null;
int number = GetJoystickNumber(Path.GetFileName(path));
if (number >= 0)
{
int fd = -1;
try
{
@ -153,12 +254,39 @@ namespace OpenTK.Platform.X11
int buttons = 0;
UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Buttons, ref buttons);
stick = new JoystickDevice<X11JoyDetails>(fd, axes, 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
@ -166,12 +294,85 @@ namespace OpenTK.Platform.X11
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();
}