From 427b3641a01cb57256a6a0e71159e27b29b52517 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Wed, 18 Dec 2013 15:50:59 +0100 Subject: [PATCH 001/154] Implemented SDL2 Joystick and GameController events --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 152 +++++++++++++++++++++++++--- 1 file changed, 138 insertions(+), 14 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 9bf07558..60e72876 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -500,6 +500,53 @@ namespace OpenTK.Platform.SDL2 LASTEVENT = 0xFFFF } + enum GameControllerAxis : byte + { + Invalid = 0xff, + LeftX = 0, + LeftY, + RightX, + RightY, + TriggerLeft, + TriggerRight, + Max + } + + enum GameControllerButton : byte + { + INVALID = 0xff, + A = 0, + B, + X, + Y, + BACK, + GUIDE, + START, + LEFTSTICK, + RIGHTSTICK, + LEFTSHOULDER, + RIGHTSHOULDER, + DPAD_UP, + DPAD_DOWN, + DPAD_LEFT, + DPAD_RIGHT, + Max + } + + [Flags] + enum HatPosition : byte + { + Centered = 0x00, + Up = 0x01, + Right = 0x02, + Down = 0x03, + Left = 0x04, + RightUp = Right | Up, + RightDown = Right | Down, + LeftUp = Left | Up, + LeftDown = Left | Down + } + enum Keycode { UNKNOWN = 0, @@ -1079,6 +1126,41 @@ namespace OpenTK.Platform.SDL2 #region Structs + struct ControllerAxisEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public GameControllerAxis Axis; + byte padding1; + byte padding2; + byte padding3; + public short Value; + ushort padding4; + } + + struct ControllerButtonEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public GameControllerButton Button; + public State State; + byte padding1; + byte padding2; + } + + struct ControllerDeviceEvent + { + public EventType Type; + public uint Timestamp; + + /// + /// The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event + /// + public int Which; + } + struct DisplayMode { public uint Format; @@ -1109,21 +1191,21 @@ namespace OpenTK.Platform.SDL2 public MouseWheelEvent Wheel; [FieldOffset(0)] public JoyAxisEvent JoyAxis; + [FieldOffset(0)] + public JoyBallEvent JoyBall; + [FieldOffset(0)] + public JoyHatEvent JoyHat; + [FieldOffset(0)] + public JoyButtonEvent JoyButton; + [FieldOffset(0)] + public JoyDeviceEvent JoyDevice; + [FieldOffset(0)] + public ControllerAxisEvent ControllerAxis; + [FieldOffset(0)] + public ControllerButtonEvent ControllerButton; + [FieldOffset(0)] + public ControllerDeviceEvent ControllerDevice; #if false - [FieldOffset(0)] - public JoyBallEvent jball; - [FieldOffset(0)] - public JoyHatEvent jhat; - [FieldOffset(0)] - public JoyButtonEvent jbutton; - [FieldOffset(0)] - public JoyDeviceEvent jdevice; - [FieldOffset(0)] - public ControllerAxisEvent caxis; - [FieldOffset(0)] - public ControllerButtonEvent cbutton; - [FieldOffset(0)] - public ControllerDeviceEvent cdevice; [FieldOffset(0)] public QuitEvent quit; [FieldOffset(0)] @@ -1154,6 +1236,48 @@ namespace OpenTK.Platform.SDL2 UInt16 padding4; } + struct JoyBallEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public byte Ball; + byte padding1; + byte padding2; + byte padding3; + public short Xrel; + public short Yrel; + } + + struct JoyButtonEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public byte Button; + public State State; + byte padding1; + byte padding2; + } + + struct JoyDeviceEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + } + + struct JoyHatEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public byte Hat; + public HatPosition Value; + byte padding1; + byte padding2; + } + struct KeyboardEvent { public EventType Type; From 9dd97cb3e1b087c61d7df7a78da022ed28e84563 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Wed, 18 Dec 2013 17:16:29 +0100 Subject: [PATCH 002/154] Use SDL2 event API for joystick devices --- .../OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 38 +++- .../Platform/SDL2/Sdl2JoystickDriver.cs | 211 ++++++++++++++---- 2 files changed, 204 insertions(+), 45 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index 7a571b14..de174875 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -92,6 +92,42 @@ namespace OpenTK.Platform.SDL2 case EventType.MOUSEWHEEL: driver.mouse_driver.ProcessWheelEvent(ev.Wheel); break; + + case EventType.JOYDEVICEADDED: + case EventType.JOYDEVICEREMOVED: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyDevice); + break; + + case EventType.JOYAXISMOTION: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyAxis); + break; + + case EventType.JOYBALLMOTION: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyBall); + break; + + case EventType.JOYBUTTONDOWN: + case EventType.JOYBUTTONUP: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyButton); + break; + + case EventType.JOYHATMOTION: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyHat); + break; + + case EventType.CONTROLLERDEVICEADDED: + case EventType.CONTROLLERDEVICEREMOVED: + driver.joystick_driver.ProcessControllerEvent(ev.ControllerDevice); + break; + + case EventType.CONTROLLERAXISMOTION: + driver.joystick_driver.ProcessControllerEvent(ev.ControllerAxis); + break; + + case EventType.CONTROLLERBUTTONDOWN: + case EventType.CONTROLLERBUTTONUP: + driver.joystick_driver.ProcessControllerEvent(ev.ControllerButton); + break; } } } @@ -172,7 +208,7 @@ namespace OpenTK.Platform.SDL2 { get { - throw new NotImplementedException(); + return joystick_driver; } } diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 729cee13..380bbd67 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -40,6 +40,7 @@ namespace OpenTK.Platform.SDL2 public float RangeMultiplier { get { return 1.0f / 32768.0f; } } public int HatCount { get; set; } public int BallCount { get; set; } + public bool IsConnected { get; set; } } readonly List joysticks = new List(); @@ -49,42 +50,181 @@ namespace OpenTK.Platform.SDL2 public Sdl2JoystickDriver() { joysticks_readonly = joysticks.AsReadOnly(); - - RefreshJoysticks(); - } #region Private Members - void RefreshJoysticks() + JoystickDevice OpenJoystick(int id) { - joysticks.Clear(); + JoystickDevice joystick = null; + int num_axes = 0; + int num_buttons = 0; + int num_hats = 0; + int num_balls = 0; - int count = SDL.NumJoysticks(); - for (int i = 0; i < count; i++) + IntPtr handle = SDL.JoystickOpen(id); + if (handle != IntPtr.Zero) { - JoystickDevice joystick = null; - int num_axes = 0; - int num_buttons = 0; - int num_hats = 0; - int num_balls = 0; + num_axes = SDL.JoystickNumAxes(handle); + num_buttons = SDL.JoystickNumButtons(handle); + num_hats = SDL.JoystickNumHats(handle); + num_balls = SDL.JoystickNumBalls(handle); - IntPtr handle = SDL.JoystickOpen(i); - if (handle != IntPtr.Zero) - { - num_axes = SDL.JoystickNumAxes(handle); - num_buttons = SDL.JoystickNumButtons(handle); - num_hats = SDL.JoystickNumHats(handle); - num_balls = SDL.JoystickNumBalls(handle); + joystick = new JoystickDevice(id, num_axes, num_buttons); + joystick.Description = SDL.JoystickName(handle); + joystick.Details.Handle = handle; + joystick.Details.HatCount = num_hats; + joystick.Details.BallCount = num_balls; - joystick = new JoystickDevice(i, num_axes, num_buttons); - joystick.Description = SDL.JoystickName(handle); - joystick.Details.Handle = handle; - joystick.Details.HatCount = num_hats; - joystick.Details.BallCount = num_balls; - joysticks.Add(joystick); - } + Debug.Print("[SDL2] Joystick device {0} opened successfully. ", id); + Debug.Print("\t\t'{0}' has {1} axes, {2} buttons, {3} hats, {4} balls", + joystick.Description, joystick.Axis.Count, joystick.Button.Count, + joystick.Details.HatCount, joystick.Details.BallCount); } + else + { + Debug.Print("[SDL2] Failed to open joystick device {0}", id); + } + + return joystick; + } + + bool IsJoystickValid(int id) + { + return id >= 0 && id < joysticks.Count; + } + + #endregion + + #region Public Members + + public void ProcessJoystickEvent(JoyDeviceEvent ev) + { + int id = ev.Which; + if (id < 0) + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + return; + } + + switch (ev.Type) + { + case EventType.JOYDEVICEADDED: + { + // Make sure we have enough space to store this instance + if (joysticks.Count <= id) + { + joysticks.Capacity = OpenTK.MathHelper.NextPowerOfTwo(id); + } + + IntPtr handle = SDL.JoystickOpen(id); + if (handle != IntPtr.Zero) + { + JoystickDevice joystick = OpenJoystick(id); + if (joysticks != null) + { + joystick.Details.IsConnected = true; + joysticks[id] = joystick; + } + } + } + break; + + case EventType.JOYDEVICEREMOVED: + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + joystick.Details.IsConnected = false; + } + break; + } + } + + public void ProcessJoystickEvent(JoyAxisEvent ev) + { + int id = ev.Which; + if (IsJoystickValid(id)) + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + float value = ev.Value * joystick.Details.RangeMultiplier; + joystick.SetAxis((JoystickAxis)ev.Axis, value); + } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } + } + + public void ProcessJoystickEvent(JoyBallEvent ev) + { + int id = ev.Which; + if (IsJoystickValid(id)) + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + // Todo: does it make sense to support balls? + } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } + } + + public void ProcessJoystickEvent(JoyButtonEvent ev) + { + int id = ev.Which; + if (IsJoystickValid(id)) + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + joystick.SetButton((JoystickButton)ev.Button, ev.State == State.Pressed); + } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } + } + + public void ProcessJoystickEvent(JoyHatEvent ev) + { + int id = ev.Which; + if (IsJoystickValid(id)) + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + // Todo: map hat to an extra axis + } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } + } + + public void ProcessControllerEvent(ControllerDeviceEvent ev) + { + int id = ev.Which; + + switch (ev.Type) + { + case EventType.CONTROLLERDEVICEADDED: + break; + + case EventType.CONTROLLERDEVICEREMOVED: + break; + + case EventType.CONTROLLERDEVICEREMAPPED: + break; + } + } + + public void ProcessControllerEvent(ControllerAxisEvent ev) + { + int id = ev.Which; + + + } + + public void ProcessControllerEvent(ControllerButtonEvent ev) + { + int id = ev.Which; + + } #endregion @@ -101,24 +241,7 @@ namespace OpenTK.Platform.SDL2 public void Poll() { - SDL.JoystickUpdate(); - foreach (var j in joysticks) - { - var joystick = (JoystickDevice)j; - IntPtr handle = joystick.Details.Handle; - - for (int i = 0; i < joystick.Axis.Count; i++) - { - var axis = JoystickAxis.Axis0 + i; - joystick.SetAxis(axis, SDL.JoystickGetAxis(handle, i) * joystick.Details.RangeMultiplier); - } - - for (int i = 0; i < joystick.Button.Count; i++) - { - var button = JoystickButton.Button0 + i; - joystick.SetButton(button, SDL.JoystickGetButton(handle, i) != 0); - } - } + // Do nothing } #endregion From 9b98228240f3f281b119f43be49abb22f5a6e05f Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 19 Dec 2013 10:42:12 +0100 Subject: [PATCH 003/154] Implemented GameController API bindings --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 54 +++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 60e72876..2232e686 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -23,8 +23,6 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // -using System.Runtime.InteropServices; - #endregion @@ -118,6 +116,49 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_FreeSurface", ExactSpelling = true)] public static extern void FreeSurface(IntPtr surface); + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerName", ExactSpelling = true)] + static extern IntPtr GameControllerNameInternal(IntPtr gamecontroller); + + /// + /// Return the name for an openend game controller instance. + /// + /// The name of the game controller name. + /// Pointer to a game controller instance returned by GameControllerOpen. + public static string GameControllerName(IntPtr gamecontroller) + { + unsafe + { + return new string((sbyte*)GameControllerNameInternal(gamecontroller)); + } + } + + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetAxis", ExactSpelling = true)] + public static extern short GameControllerGetAxis(IntPtr gamecontroller, GameControllerAxis axis); + + /// > + /// Gets the current state of a button on a game controller. + /// + /// A game controller handle previously opened with GameControllerOpen. + /// A zero-based GameControllerButton value. + /// true if the specified button is pressed; false otherwise. + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetButton", ExactSpelling = true)] + public static extern bool GameControllerGetButton(IntPtr gamecontroller, GameControllerButton button); + + /// + /// Opens a game controller for use. + /// + /// + /// A zero-based index for the game controller. + /// This index is the value which will identify this controller in future controller events. + /// + /// A handle to the game controller instance, or IntPtr.Zero in case of error. + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerOpen", ExactSpelling = true)] + public static extern IntPtr GameControllerOpen(int joystick_index); + [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetCurrentDisplayMode", ExactSpelling = true)] public static extern int GetCurrentDisplayMode(int displayIndex, out DisplayMode mode); @@ -192,6 +233,15 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_Init", ExactSpelling = true)] public static extern int Init(SystemFlags flags); + /// + /// Determines if the specified joystick is supported by the GameController API. + /// + /// true if joystick_index is supported by the GameController API; false otherwise. + /// The index of the joystick to check. + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_IsGameController", ExactSpelling = true)] + public static extern bool IsGameController(int joystick_index); + [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickClose", ExactSpelling = true)] public static extern void JoystickClose(IntPtr joystick); From a4d7d79b95f4be1b51fd913759f050171066428f Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 19 Dec 2013 16:27:26 +0100 Subject: [PATCH 004/154] Updated internal IGamePadDriver interface --- Source/OpenTK/Input/IGamePadDriver.cs | 14 +--- .../Platform/SDL2/Sdl2JoystickDriver.cs | 66 ++++++++++++++++--- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 9 ++- Source/OpenTK/Platform/X11/X11Joystick.cs | 10 +-- 4 files changed, 71 insertions(+), 28 deletions(-) diff --git a/Source/OpenTK/Input/IGamePadDriver.cs b/Source/OpenTK/Input/IGamePadDriver.cs index 718d1bc1..fc24c8f8 100644 --- a/Source/OpenTK/Input/IGamePadDriver.cs +++ b/Source/OpenTK/Input/IGamePadDriver.cs @@ -6,19 +6,11 @@ namespace OpenTK.Input { interface IGamePadDriver { - /// - /// Retrieves the combined for all gamepad devices. - /// - /// A structure containing the combined state for all gamepad devices. - GamePadState GetState(); - /// - /// Retrieves the for the specified gamepad device. - /// - /// The index of the keyboard device. - /// A structure containing the state of the gamepad device. GamePadState GetState(int index); + GamePadCapabilities GetCapabilities(int index); + /// /// Retrieves the device name for the gamepad device. /// @@ -26,6 +18,6 @@ namespace OpenTK.Input /// A with the name of the specified device or . /// /// If no device exists at the specified index, the return value is . - string GetDeviceName(int index); + string GetName(int index); } } diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 380bbd67..2af3f977 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -34,18 +34,32 @@ namespace OpenTK.Platform.SDL2 { class Sdl2JoystickDriver : IJoystickDriver, IGamePadDriver, IDisposable { + const float RangeMultiplier = 1.0f / 32768.0f; + struct Sdl2JoystickDetails { public IntPtr Handle { get; set; } - public float RangeMultiplier { get { return 1.0f / 32768.0f; } } public int HatCount { get; set; } public int BallCount { get; set; } public bool IsConnected { get; set; } } + class Sdl2GamePad + { + public IntPtr Handle { get; private set; } + public GamePadState State { get; set; } + + public Sdl2GamePad(IntPtr handle) + { + Handle = handle; + } + } + readonly List joysticks = new List(); + readonly Dictionary controllers = new Dictionary(); + IList joysticks_readonly; - bool disposed = false; + bool disposed; public Sdl2JoystickDriver() { @@ -94,6 +108,11 @@ namespace OpenTK.Platform.SDL2 return id >= 0 && id < joysticks.Count; } + bool IsControllerValid(int id) + { + return controllers.ContainsKey(id); + } + #endregion #region Public Members @@ -145,7 +164,7 @@ namespace OpenTK.Platform.SDL2 if (IsJoystickValid(id)) { JoystickDevice joystick = (JoystickDevice)joysticks[id]; - float value = ev.Value * joystick.Details.RangeMultiplier; + float value = ev.Value * RangeMultiplier; joystick.SetAxis((JoystickAxis)ev.Axis, value); } else @@ -203,12 +222,27 @@ namespace OpenTK.Platform.SDL2 switch (ev.Type) { case EventType.CONTROLLERDEVICEADDED: + if (SDL.IsGameController(id)) + { + IntPtr handle = SDL.GameControllerOpen(id); + if (handle != IntPtr.Zero) + { + Sdl2GamePad pad = new Sdl2GamePad(handle); + pad.State.SetConnected(true); + controllers.Add(id, pad); + } + } break; case EventType.CONTROLLERDEVICEREMOVED: + if (IsControllerValid(id)) + { + controllers[id].State.SetConnected(false); + } break; case EventType.CONTROLLERDEVICEREMAPPED: + // Todo: what should we do in this case? break; } } @@ -216,15 +250,27 @@ namespace OpenTK.Platform.SDL2 public void ProcessControllerEvent(ControllerAxisEvent ev) { int id = ev.Which; - - + if (IsControllerValid(id)) + { + controllers[id].State.SetAxis((GamePadAxis)ev.Axis, ev.Value); + } + else + { + Debug.Print("[SDL2] Invalid game controller handle {0} in {1}", id, ev.Type); + } } public void ProcessControllerEvent(ControllerButtonEvent ev) { int id = ev.Which; - - + if (IsControllerValid(id)) + { + controllers[id].State.SetButton((Buttons)ev.Button, ev.State == State.Pressed); + } + else + { + Debug.Print("[SDL2] Invalid game controller handle {0} in {1}", id, ev.Type); + } } #endregion @@ -248,9 +294,9 @@ namespace OpenTK.Platform.SDL2 #region IGamePadDriver Members - public GamePadState GetState() + public GamePadCapabilities GetCapabilities(int index) { - return new GamePadState(); + return new GamePadCapabilities(); } public GamePadState GetState(int index) @@ -263,7 +309,7 @@ namespace OpenTK.Platform.SDL2 return new GamePadState(); } - public string GetDeviceName(int index) + public string GetName(int index) { return String.Empty; } diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 32a00c7a..ca229700 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -428,8 +428,9 @@ namespace OpenTK.Platform.Windows #endregion - //HACK implement - public GamePadState GetState() + #region IGamePadDriver Members + + public GamePadCapabilities GetCapabilities(int index) { throw new NotImplementedException(); } @@ -439,9 +440,11 @@ namespace OpenTK.Platform.Windows throw new NotImplementedException(); } - public string GetDeviceName(int index) + public string GetName(int index) { throw new NotImplementedException(); } + + #endregion } } diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs index 85299eb1..b4948169 100644 --- a/Source/OpenTK/Platform/X11/X11Joystick.cs +++ b/Source/OpenTK/Platform/X11/X11Joystick.cs @@ -259,21 +259,23 @@ namespace OpenTK.Platform.X11 #endregion - //HACK implement - public GamePadState GetState() + #region IGamePadDriver Members + + public GamePadCapabilities GetCapabilities(int index) { throw new NotImplementedException(); } public GamePadState GetState(int index) { - Poll(); throw new NotImplementedException(); } - public string GetDeviceName(int index) + public string GetName(int index) { throw new NotImplementedException(); } + + #endregion } } From 9374b6b41b0c773ae3cf31c3c0b4edeaf5f1b5c6 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 19 Dec 2013 16:27:57 +0100 Subject: [PATCH 005/154] Implemented GamePadButtons --- Source/OpenTK/Input/Buttons.cs | 213 ++++++++++++++++++++++++++ Source/OpenTK/Input/GamePadButton.cs | 68 -------- Source/OpenTK/Input/GamePadButtons.cs | 131 ++++++++++++++++ 3 files changed, 344 insertions(+), 68 deletions(-) create mode 100644 Source/OpenTK/Input/Buttons.cs delete mode 100644 Source/OpenTK/Input/GamePadButton.cs create mode 100644 Source/OpenTK/Input/GamePadButtons.cs diff --git a/Source/OpenTK/Input/Buttons.cs b/Source/OpenTK/Input/Buttons.cs new file mode 100644 index 00000000..739a8fcd --- /dev/null +++ b/Source/OpenTK/Input/Buttons.cs @@ -0,0 +1,213 @@ +// +// GamePadButton.cs +// +// Author: +// robert <${AuthorEmail}> +// +// Copyright (c) 2012 robert +// +// 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. +using System; + +namespace OpenTK.Input +{ + public enum Buttons + { + /// + /// DPad up direction button + /// + DPadUp = 1 << 0, + + /// + /// DPad down direction button + /// + DPadDown = 1 << 1, + + /// + /// DPad left direction button + /// + DPadLeft = 1 << 2, + + /// + /// DPad right direction button + /// + DPadRight = 1 << 3, + + /// + /// Start button + /// + Start = 1 << 4, + + /// + /// Back button + /// + Back = 1 << 5, + + /// + /// Left stick button + /// + LeftStick = 1 << 6, + + /// + /// Right stick button + /// + RightStick = 1 << 7, + + /// + /// Left shoulder button + /// + LeftShoulder = 1 << 8, + + /// + /// Right shoulder button + /// + RightShoulder = 1 << 9, + + /// + /// Home button + /// + Home = 1 << 11, + + /// + /// Home button + /// + BigButton = Home, + + /// + /// A button + /// + A = 1 << 12, + + /// + /// B button + /// + B = 1 << 13, + + /// + /// X button + /// + X = 1 << 14, + + /// + /// Y button + /// + Y = 1 << 15, + + /// + /// Left thumbstick left direction button + /// + LeftThumbstickLeft = 1 << 21, + + /// + /// Right trigger button + /// + RightTrigger = 1 << 22, + + /// + /// Left trigger button + /// + LeftTrigger = 1 << 23, + + /// + /// Right thumbstick up direction button + /// + RightThumbstickUp = 1 << 24, + + /// + /// Right thumbstick down direction button + /// + RightThumbstickDown = 1 << 25, + + /// + /// Right stick right direction button + /// + RightThumbstickRight = 1 << 26, + + /// + /// Right stick left direction button + /// + RightThumbstickLeft = 1 << 27, + + /// + /// Left stick up direction button + /// + LeftThumbstickUp = 1 << 28, + + /// + /// Left stick down direction button + /// + LeftThumbstickDown = 1 << 29, + + /// + /// Left stick right direction button + /// + LeftThumbstickRight = 1 << 30, + + /// The first button of the gamepad. + Button0 = A, + /// The second button of the gamepad. + Button1 = B, + /// The third button of the gamepad. + Button2 = X, + /// The fourth button of the gamepad. + Button3 = Y, + /// The fifth button of the gamepad. + Button4 = Start, + /// The sixth button of the gamepad. + Button5 = Back, + /// The seventh button of the gamepad. + Button6 = LeftStick, + /// The eighth button of the gamepad. + Button7 = RightStick, + /// The ninth button of the gamepad. + Button8 = LeftShoulder, + /// The tenth button of the gamepad. + Button9 = RightShoulder, + /// The eleventh button of the gamepad. + Button10 = Home, + /// The twelfth button of the gamepad. + Button11 = DPadUp, + /// The thirteenth button of the gamepad. + Button12 = DPadDown, + /// The fourteenth button of the gamepad. + Button13 = DPadLeft, + /// The fifteenth button of the gamepad. + Button14 = DPadRight, + /// The sixteenth button of the gamepad. + Button15 = LeftTrigger, + /// The seventeenth button of the gamepad. + Button16 = RightTrigger, + /// The eighteenth button of the gamepad. + Button17 = LeftThumbstickUp, + /// The nineteenth button of the gamepad. + Button18 = LeftThumbstickDown, + /// The twentieth button of the gamepad. + Button19 = LeftThumbstickLeft, + /// The twentieth-one button of the gamepad. + Button20 = LeftThumbstickRight, + /// The twentieth-one button of the gamepad. + Button21 = RightThumbstickUp, + /// The twentieth-one button of the gamepad. + Button22 = RightThumbstickDown, + /// The twentieth-one button of the gamepad. + Button23 = RightThumbstickLeft, + /// The twentieth-one button of the gamepad. + Button24 = RightThumbstickRight, + } +} diff --git a/Source/OpenTK/Input/GamePadButton.cs b/Source/OpenTK/Input/GamePadButton.cs deleted file mode 100644 index f4f543ad..00000000 --- a/Source/OpenTK/Input/GamePadButton.cs +++ /dev/null @@ -1,68 +0,0 @@ -// -// GamePadButton.cs -// -// Author: -// robert <${AuthorEmail}> -// -// Copyright (c) 2012 robert -// -// 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. -using System; - -namespace OpenTK -{ - public enum GamePadButton - { - /// The first button of the gamepad. - Button0 = 0, - /// The second button of the gamepad. - Button1, - /// The third button of the gamepad. - Button2, - /// The fourth button of the gamepad. - Button3, - /// The fifth button of the gamepad. - Button4, - /// The sixth button of the gamepad. - Button5, - /// The seventh button of the gamepad. - Button6, - /// The eighth button of the gamepad. - Button7, - /// The ninth button of the gamepad. - Button8, - /// The tenth button of the gamepad. - Button9, - /// The eleventh button of the gamepad. - Button10, - /// The twelfth button of the gamepad. - Button11, - /// The thirteenth button of the gamepad. - Button12, - /// The fourteenth button of the gamepad. - Button13, - /// The fifteenth button of the gamepad. - Button14, - /// The sixteenth button of the gamepad. - Button15, - /// The last button of the gamepad. - LastButton - } -} - diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs new file mode 100644 index 00000000..199e593f --- /dev/null +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -0,0 +1,131 @@ +// #region License +// +// GamePadButtons.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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; + +namespace OpenTK.Input +{ + + public struct GamePadButtons : IEquatable + { + Buttons buttons; + + public GamePadButtons(Buttons state) + { + buttons = state; + } + + #region Public Members + + public ButtonState A + { + get { return GetButton(Buttons.A); } + } + + public ButtonState B + { + get { return GetButton(Buttons.B); } + } + + public ButtonState X + { + get { return GetButton(Buttons.X); } + } + + public ButtonState Y + { + get { return GetButton(Buttons.Y); } + } + + public ButtonState Back + { + get { return GetButton(Buttons.Back); } + } + + public ButtonState BigButton + { + get { return GetButton(Buttons.BigButton); } + } + + public ButtonState LeftShoulder + { + get { return GetButton(Buttons.LeftShoulder); } + } + + public ButtonState LeftStick + { + get { return GetButton(Buttons.LeftStick); } + } + + public ButtonState RightShoulder + { + get { return GetButton(Buttons.RightShoulder); } + } + + public ButtonState RightStick + { + get { return GetButton(Buttons.RightStick); } + } + + public ButtonState Start + { + get { return GetButton(Buttons.Start); } + } + + public static bool operator ==(GamePadButtons left, GamePadButtons right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadButtons left, GamePadButtons right) + { + return !left.Equals(right); + } + + #endregion + + #region IEquatable Members + + public bool Equals(GamePadButtons other) + { + return buttons == other.buttons; + } + + #endregion + + #region Private Members + + ButtonState GetButton(Buttons b) + { + return (buttons & b) != 0 ? ButtonState.Pressed : ButtonState.Released; + } + + #endregion + } +} + From c8989f3e0d3f219ddd59a8e60fa8f3aba909b10a Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 19 Dec 2013 16:28:20 +0100 Subject: [PATCH 006/154] Implemented new GamePad interface (WIP) --- Source/OpenTK/Input/GamePad.cs | 32 +++++-- Source/OpenTK/Input/GamePadAxis.cs | 8 +- Source/OpenTK/Input/GamePadCapabilities.cs | 67 +++++++++++++++ Source/OpenTK/Input/GamePadDPad.cs | 90 ++++++++++++++++++++ Source/OpenTK/Input/GamePadState.cs | 99 ++++++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 5 +- 6 files changed, 290 insertions(+), 11 deletions(-) create mode 100644 Source/OpenTK/Input/GamePadCapabilities.cs create mode 100644 Source/OpenTK/Input/GamePadDPad.cs diff --git a/Source/OpenTK/Input/GamePad.cs b/Source/OpenTK/Input/GamePad.cs index 303f4516..7a2fc066 100644 --- a/Source/OpenTK/Input/GamePad.cs +++ b/Source/OpenTK/Input/GamePad.cs @@ -30,17 +30,39 @@ using System; namespace OpenTK.Input { /// - /// Provides access to GamePad devices. Note: this API is not implemented yet. + /// Provides access to GamePad devices. /// public class GamePad { - #region Constructors + internal const int MaxAxisCount = 10; + internal const int MaxButtonCount = 16; // if this grows over 32 then GamePadState.buttons must be modified + internal const int MaxDPadCount = 2; - static GamePad() + static readonly IGamePadDriver driver = + Platform.Factory.Default.CreateGamePadDriver(); + + /// + /// Retrieves a GamePadCapabilities structure describing the + /// capabilities of a gamepad device. + /// + /// The zero-based index of a gamepad device. + /// A GamePadCapabilities structure describing the capabilities of the gamepad device. + public static GamePadCapabilities GetCapabilities(int index) { - throw new NotImplementedException(); + if (index < 0) + throw new IndexOutOfRangeException(); + + return driver.GetCapabilities(index); } - #endregion + /// + /// Retrieves the GamePadState for the specified gamepad device. + /// + /// The zero-based index of a gamepad device. + /// A GamePadState structure describing the state of the gamepad device. + public static GamePadState GetState(int index) + { + return driver.GetState(index); + } } } diff --git a/Source/OpenTK/Input/GamePadAxis.cs b/Source/OpenTK/Input/GamePadAxis.cs index c1c96c53..dd6b3192 100644 --- a/Source/OpenTK/Input/GamePadAxis.cs +++ b/Source/OpenTK/Input/GamePadAxis.cs @@ -25,11 +25,11 @@ // THE SOFTWARE. using System; -namespace OpenTK +namespace OpenTK.Input { public enum GamePadAxis - { - /// The first axis of the gamepad. + { + /// The first axis of the gamepad. Axis0 = 0, /// The second axis of the gamepad. Axis1, @@ -49,8 +49,6 @@ namespace OpenTK Axis8, /// The tenth axis of the gamepad. Axis9, - /// The last axis of the gamepad. - LastAxis } } diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs new file mode 100644 index 00000000..23c56cd3 --- /dev/null +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -0,0 +1,67 @@ +// #region License +// +// GamePadCapabilities.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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; + +namespace OpenTK.Input +{ + + public struct GamePadCapabilities + { + byte axis_count; + byte button_count; + byte dpad_count; + byte trackball_count; + + public int AxisCount + { + get { return axis_count; } + internal set { axis_count = (byte)value; } + } + + public int ButtonCount + { + get { return button_count; } + internal set { button_count = (byte)value; } + } + + public int DPadCount + { + get { return dpad_count; } + internal set { dpad_count = (byte)value; } + } + + public int TrackballCount + { + get { return trackball_count; } + internal set { trackball_count = (byte)value; } + } + } +} + diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs new file mode 100644 index 00000000..72389b00 --- /dev/null +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -0,0 +1,90 @@ +// #region License +// +// GamePadDPad.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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; + +namespace OpenTK.Input +{ + + public struct GamePadDPad + { + [Flags] + enum DPadButtons : byte + { + Up = Buttons.DPadUp, + Down = Buttons.DPadDown, + Left = Buttons.DPadLeft, + Right = Buttons.DPadRight + } + + DPadButtons buttons; + + internal GamePadDPad(Buttons state) + { + // DPad butons are stored in the lower 4bits + // of the Buttons enumeration. + buttons = (DPadButtons)((int)state & 0x0f); + } + + public bool IsUp + { + get { return (buttons & DPadButtons.Up) != 0; } + internal set { SetButton(DPadButtons.Up, value); } + } + + public bool IsDown + { + get { return (buttons & DPadButtons.Down) != 0; } + internal set { SetButton(DPadButtons.Down, value); } + } + + public bool IsLeft + { + get { return (buttons & DPadButtons.Left) != 0; } + internal set { SetButton(DPadButtons.Left, value); } + } + + public bool IsRight + { + get { return (buttons & DPadButtons.Right) != 0; } + internal set { SetButton(DPadButtons.Right, value); } + } + + void SetButton(DPadButtons button, bool value) + { + if (value) + { + buttons |= button; + } + else + { + buttons &= ~button; + } + } + } +} diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index 21e3aa91..d45787bb 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -34,6 +34,105 @@ namespace OpenTK.Input /// public struct GamePadState /*: IEquatable*/ { + const float RangeMultiplier = 1.0f / (short.MaxValue + 1); + Buttons buttons; + unsafe fixed short axes[GamePad.MaxAxisCount]; + bool is_connected; + + #region Public Members + + public float GetAxis(GamePadAxis axis) + { + throw new NotImplementedException(); + } + + public GamePadButtons Buttons + { + get { return new GamePadButtons(buttons); } + } + + public GamePadDPad DPad + { + get { return new GamePadDPad(buttons); } + } + + public bool IsConnected + { + get { return is_connected; } + } + + #endregion + + #region Internal Members + + internal void SetAxis(GamePadAxis axis, short value) + { + if (IsAxisValid(axis)) + { + int index = (int)axis; + unsafe + { + fixed (short *paxes = axes) + { + *(paxes + index) = value; + } + } + } + else + { + throw new ArgumentOutOfRangeException("axis"); + } + } + + internal void SetButton(Buttons button, bool pressed) + { + if (IsButtonValid(button)) + { + int index = (int)button; + + Buttons mask = (Buttons)(1 << index); + if (pressed) + { + buttons |= mask; + } + else + { + buttons &= ~mask; + } + } + else + { + throw new ArgumentOutOfRangeException("button"); + } + } + + internal void SetConnected(bool connected) + { + is_connected = connected; + } + + #endregion + + #region Private Members + + bool IsAxisValid(GamePadAxis axis) + { + int index = (int)axis; + return index >= 0 && index < GamePad.MaxAxisCount; + } + + bool IsButtonValid(Buttons button) + { + int index = (int)button; + return index >= 0 && index < GamePad.MaxButtonCount; + } + + bool IsDPadValid(int index) + { + return index >= 0 && index < GamePad.MaxDPadCount; + } + + #endregion } } diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 7bddfcb0..723b4412 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -738,7 +738,6 @@ - @@ -777,6 +776,10 @@ + + + + From 234c15e9c9d0352357ec612c7fcff9401a4d446b Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 17 Dec 2013 16:38:56 +0100 Subject: [PATCH 007/154] Corrected the entrypoint for wglChoosePixelFormat --- Source/OpenTK/Platform/Windows/Bindings/Wgl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs b/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs index 4668f629..e235beb8 100644 --- a/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs +++ b/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs @@ -49,11 +49,11 @@ namespace OpenTK.Platform.Windows [DllImport(Wgl.Library, EntryPoint = "wglMakeCurrent", ExactSpelling = true, SetLastError = true)] internal extern static Boolean MakeCurrent(IntPtr hDc, IntPtr newContext); [SuppressUnmanagedCodeSecurity] - [DllImport(Wgl.Library, EntryPoint = "wglCopyContext", ExactSpelling = true, SetLastError = true)] + [DllImport(Wgl.Library, EntryPoint = "wglChoosePixelFormat", ExactSpelling = true, SetLastError = true)] internal extern static unsafe int ChoosePixelFormat(IntPtr hDc, ref PixelFormatDescriptor pPfd); [SuppressUnmanagedCodeSecurity] [DllImport(Wgl.Library, EntryPoint = "wglDescribePixelFormat", ExactSpelling = true, SetLastError = true)] - internal extern static unsafe int DescribePixelFormat(IntPtr hdc, int ipfd, UInt32 cjpfd, out PixelFormatDescriptor ppfd); + internal extern static unsafe int DescribePixelFormat(IntPtr hdc, int ipfd, int cjpfd, ref PixelFormatDescriptor ppfd); [SuppressUnmanagedCodeSecurity] [DllImport(Wgl.Library, EntryPoint = "wglGetCurrentDC", ExactSpelling = true, SetLastError = true)] internal extern static IntPtr GetCurrentDC(); From 1c8e7bc9931ef9c89e003f4c36b04eb5b7724d3c Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 17 Dec 2013 16:39:45 +0100 Subject: [PATCH 008/154] Use opengl32 instead of gdi32 throughout Since we are dynamically loading opengl32.dll, we are supposed to use the wgl version of functions that exist in both opengl32 and gdi32 dlls. --- Source/OpenTK/Platform/Windows/WinGLContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index e431ae6b..a534d929 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -389,13 +389,13 @@ namespace OpenTK.Platform.Windows } PixelFormatDescriptor pfd = new PixelFormatDescriptor(); - Functions.DescribePixelFormat( + Wgl.DescribePixelFormat( window.DeviceContext, (int)mode.Index.Value, API.PixelFormatDescriptorSize, ref pfd); Debug.WriteLine(mode.Index.ToString()); - if (!Functions.SetPixelFormat(window.DeviceContext, (int)mode.Index.Value, ref pfd)) + if (!Wgl.SetPixelFormat(window.DeviceContext, (int)mode.Index.Value, ref pfd)) { throw new GraphicsContextException(String.Format( "Requested GraphicsMode not available. SetPixelFormat error: {0}", From 954b1e98b63239f2b188f200c31733beeb3e0fe6 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 17 Dec 2013 16:40:15 +0100 Subject: [PATCH 009/154] Minor code cleanup No need to wrap Wgl.DescribePixelFormat, just call it directly. --- Source/OpenTK/Platform/Windows/WinGraphicsMode.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index 67f3ce19..f62f2315 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -105,17 +105,6 @@ namespace OpenTK.Platform.Windows #region Private Methods - #region DescribePixelFormat - - static int DescribePixelFormat(IntPtr hdc, int ipfd, int cjpfd, ref PixelFormatDescriptor pfd) - { - // Note: DescribePixelFormat found in gdi32 is extremely slow - // on nvidia, for some reason. - return Wgl.DescribePixelFormat(hdc, ipfd, (uint)cjpfd, out pfd); - } - - #endregion - #region GetModesPFD IEnumerable GetModesPFD(IntPtr device) @@ -140,8 +129,9 @@ namespace OpenTK.Platform.Windows { // Iterate through all accelerated formats first. Afterwards, iterate through non-accelerated formats. // This should fix issue #2224, which causes OpenTK to fail on VMs without hardware acceleration. + // Note: DescribePixelFormat found in gdi32 is extremely slow on nvidia, for some reason. int pixel = 0; - while (DescribePixelFormat(device, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0) + while (Wgl.DescribePixelFormat(device, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0) { // Ignore non-accelerated formats. if (!generic_allowed && (pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) From 3413271d8abec58d2369080cd0348128b2355709 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 17 Dec 2013 21:24:25 +0100 Subject: [PATCH 010/154] Load opengl32.dll before gdi32.dll According to http://stackoverflow.com/questions/199016/wglcreatecontext-in-c-sharp-failing-but-not-in-managed-c, opengl32.dll must be loaded before gdi32.dll. Affect issue #19. --- Source/OpenTK/Platform/Windows/WinFactory.cs | 20 +++++++++++++++++++ .../OpenTK/Platform/Windows/WinGLContext.cs | 17 ++-------------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinFactory.cs b/Source/OpenTK/Platform/Windows/WinFactory.cs index b0fc8224..5435018c 100644 --- a/Source/OpenTK/Platform/Windows/WinFactory.cs +++ b/Source/OpenTK/Platform/Windows/WinFactory.cs @@ -34,6 +34,7 @@ namespace OpenTK.Platform.Windows { using Graphics; using OpenTK.Input; + using System.Runtime.InteropServices; class WinFactory : IPlatformFactory { @@ -41,6 +42,9 @@ namespace OpenTK.Platform.Windows readonly object SyncRoot = new object(); IInputDriver2 inputDriver; + internal static IntPtr OpenGLHandle { get; private set; } + const string OpenGLName = "OPENGL32.DLL"; + public WinFactory() { if (System.Environment.OSVersion.Version.Major <= 4) @@ -48,6 +52,11 @@ namespace OpenTK.Platform.Windows throw new PlatformNotSupportedException("OpenTK requires Windows XP or higher"); } + // Dynamically load opengl32.dll in order to use the extension loading capabilities of Wgl. + // Note: opengl32.dll must be loaded before gdi32.dll, otherwise strange failures may occur + // (such as "error: 2000" when calling wglSetPixelFormat or slowness/lag on specific GPUs). + LoadOpenGL(); + if (System.Environment.OSVersion.Version.Major >= 6) { if (Toolkit.Options.EnableHighResolution) @@ -60,6 +69,17 @@ namespace OpenTK.Platform.Windows } } + static void LoadOpenGL() + { + OpenGLHandle = Functions.LoadLibrary(OpenGLName); + if (OpenGLHandle == IntPtr.Zero) + { + throw new ApplicationException(String.Format("LoadLibrary(\"{0}\") call failed with code {1}", + OpenGLName, Marshal.GetLastWin32Error())); + } + Debug.WriteLine(String.Format("Loaded opengl32.dll: {0}", OpenGLHandle)); + } + #region IPlatformFactory Members public virtual INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index a534d929..bfe4c9d1 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -30,9 +30,6 @@ namespace OpenTK.Platform.Windows static readonly object LoadLock = new object(); static readonly object SyncRoot = new object(); - static IntPtr opengl32Handle; - const string opengl32Name = "OPENGL32.DLL"; - bool vsync_supported; readonly WinGraphicsMode ModeSelector; @@ -43,16 +40,6 @@ namespace OpenTK.Platform.Windows { lock (LoadLock) { - // Dynamically load opengl32.dll in order to use the extension loading capabilities of Wgl. - if (opengl32Handle == IntPtr.Zero) - { - opengl32Handle = Functions.LoadLibrary(opengl32Name); - if (opengl32Handle == IntPtr.Zero) - throw new ApplicationException(String.Format("LoadLibrary(\"{0}\") call failed with code {1}", - opengl32Name, Marshal.GetLastWin32Error())); - Debug.WriteLine(String.Format("Loaded opengl32.dll: {0}", opengl32Handle)); - } - // We need to create a temp context in order to load // wgl extensions (e.g. for multisampling or GL3). // We cannot rely on OpenTK.Platform.Wgl until we @@ -341,7 +328,7 @@ namespace OpenTK.Platform.Windows IntPtr address = Wgl.GetProcAddress(function_string); if (!IsValid(address)) { - address = Functions.GetProcAddress(opengl32Handle, function_string); + address = Functions.GetProcAddress(WinFactory.OpenGLHandle, function_string); } return address; } @@ -351,7 +338,7 @@ namespace OpenTK.Platform.Windows IntPtr address = Wgl.GetProcAddress(function_string); if (!IsValid(address)) { - address = Functions.GetProcAddress(opengl32Handle, function_string); + address = Functions.GetProcAddress(WinFactory.OpenGLHandle, function_string); } return address; } From 613ca93d894823581668a918e03e4161609778bc Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 17 Dec 2013 22:35:30 +0100 Subject: [PATCH 011/154] Use gdi32 implementations of functions Several functions are defined in both gdi32 and opengl32. Using the opengl32/wgl versions did not appear to help with issue #19. Let's use the gdi32 version instead, as suggested here: https://www.opengl.org/wiki/Platform_specifics:_Windows#The_WGL_functions --- Source/OpenTK/Platform/Windows/WinGLContext.cs | 6 +++--- Source/OpenTK/Platform/Windows/WinGraphicsMode.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index bfe4c9d1..92c21851 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -376,13 +376,13 @@ namespace OpenTK.Platform.Windows } PixelFormatDescriptor pfd = new PixelFormatDescriptor(); - Wgl.DescribePixelFormat( + Functions.DescribePixelFormat( window.DeviceContext, (int)mode.Index.Value, API.PixelFormatDescriptorSize, ref pfd); Debug.WriteLine(mode.Index.ToString()); - - if (!Wgl.SetPixelFormat(window.DeviceContext, (int)mode.Index.Value, ref pfd)) + + if (!Functions.SetPixelFormat(window.DeviceContext, (int)mode.Index.Value, ref pfd)) { throw new GraphicsContextException(String.Format( "Requested GraphicsMode not available. SetPixelFormat error: {0}", diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index f62f2315..b2826b5e 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -131,7 +131,7 @@ namespace OpenTK.Platform.Windows // This should fix issue #2224, which causes OpenTK to fail on VMs without hardware acceleration. // Note: DescribePixelFormat found in gdi32 is extremely slow on nvidia, for some reason. int pixel = 0; - while (Wgl.DescribePixelFormat(device, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0) + while (Functions.DescribePixelFormat(device, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0) { // Ignore non-accelerated formats. if (!generic_allowed && (pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) From 4ced172bdcc46be1ca278ec70be3dd5764da211b Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 17 Dec 2013 23:31:04 +0100 Subject: [PATCH 012/154] Minor code cleanup --- Source/OpenTK/Platform/Windows/WinFactory.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinFactory.cs b/Source/OpenTK/Platform/Windows/WinFactory.cs index 5435018c..5ea1a8eb 100644 --- a/Source/OpenTK/Platform/Windows/WinFactory.cs +++ b/Source/OpenTK/Platform/Windows/WinFactory.cs @@ -28,13 +28,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.InteropServices; using System.Text; +using OpenTK.Graphics; +using OpenTK.Input; + namespace OpenTK.Platform.Windows { - using Graphics; - using OpenTK.Input; - using System.Runtime.InteropServices; class WinFactory : IPlatformFactory { From 146e8f3fb1405623eac61ff09f0e1264ab9d2c4f Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Wed, 18 Dec 2013 14:16:49 +0100 Subject: [PATCH 013/154] Fixed GetModesARB implementation The correct way to query number of available pixel formats is to use Wgl.Arb.GetPixelFormatAttrib(NumberPixelFormatsArb), not Wgl.Arb.ChoosePixelFormats. This fixes an issue where Intel drivers would fail to report any pixel formats in GetModesARB, even when WGL_ARB_pixel_format is supported. --- .../Platform/Windows/WinGraphicsMode.cs | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index b2826b5e..0efc07ce 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -155,6 +155,11 @@ namespace OpenTK.Platform.Windows #region GetModesARB + // Queries pixel formats through the WGL_ARB_pixel_format extension + // This method only returns accelerated formats. If no format offers + // hardware acceleration (e.g. we are running in a VM or in a remote desktop + // connection), this method will return 0 formats and we will fall back to + // GetModesPFD. IEnumerable GetModesARB(IntPtr device) { // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt @@ -166,6 +171,10 @@ namespace OpenTK.Platform.Windows yield break; } + // Define the list of attributes we are interested in. + // We will use each available pixel format for these + // attributes using GetPixelFormatAttrib. + // The results will be stored in the 'values' array below. int[] attribs = new int[] { (int)WGL_ARB_pixel_format.AccelerationArb, @@ -193,46 +202,41 @@ namespace OpenTK.Platform.Windows 0 }; + // Allocate storage for the results of GetPixelFormatAttrib queries int[] values = new int[attribs.Length]; - int[] attribs_values = new int[] - { - (int)WGL_ARB_pixel_format.AccelerationArb, - (int)WGL_ARB_pixel_format.FullAccelerationArb, - (int)WGL_ARB_pixel_format.SupportOpenglArb, 1, - (int)WGL_ARB_pixel_format.DrawToWindowArb, 1, - 0, 0 - }; - - int[] num_formats = new int[1]; // Get the number of available formats - if (Wgl.Arb.ChoosePixelFormat(device, attribs_values, null, 0, null, num_formats)) + int num_formats; + int num_formats_attrib = (int)WGL_ARB_pixel_format.NumberPixelFormatsArb; + if (Wgl.Arb.GetPixelFormatAttrib(device, 0, 0, 1, ref num_formats_attrib, out num_formats)) { - // Create an array big enough to hold all available formats and get those formats - int[] pixel = new int[num_formats[0]]; - - if (Wgl.Arb.ChoosePixelFormat(device, attribs_values, null, pixel.Length, pixel, num_formats)) + for (int p = 1; p < num_formats; p++) { - foreach (int p in pixel) + // Get the format attributes for this pixel format + if (!Wgl.Arb.GetPixelFormatAttrib(device, p, 0, attribs.Length - 1, attribs, values)) { - // Find out what we really got as a format: - if (!Wgl.Arb.GetPixelFormatAttrib(device, p, 0, attribs.Length - 1, attribs, values)) - { - Debug.Print("[Warning] Failed to detect attributes for PixelFormat:{0}.", p); - continue; - } - - GraphicsMode mode = new GraphicsMode(new IntPtr(p), - new ColorFormat(values[1], values[2], values[3], values[4]), - values[6], - values[7], - values[8] != 0 ? values[9] : 0, - new ColorFormat(values[10], values[11], values[12], values[13]), - values[15] == 1 ? 2 : 1, - values[16] == 1 ? true : false); - - yield return mode; + Debug.Print("[Warning] Failed to detect attributes for PixelFormat:{0}.", p); + continue; } + + // Skip formats that don't offer full hardware acceleration + WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)attribs[0]; + if (acceleration != WGL_ARB_pixel_format.FullAccelerationArb) + { + continue; + } + + // Construct a new GraphicsMode to describe this format + GraphicsMode mode = new GraphicsMode(new IntPtr(p), + new ColorFormat(values[1], values[2], values[3], values[4]), + values[6], + values[7], + values[8] != 0 ? values[9] : 0, + new ColorFormat(values[10], values[11], values[12], values[13]), + values[15] == 1 ? 2 : 1, + values[16] == 1 ? true : false); + + yield return mode; } } } From c42090835f4b88cf14936d93ba9b43ffbc398059 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Wed, 18 Dec 2013 14:29:06 +0100 Subject: [PATCH 014/154] Cleaned up temporary context construction The temporary context is now retained until the actual context has been constructed. If we don't do this, then WGL_ARB_create_context may fail to work correctly on specific GPUs (e.g. Intel). This may affect issue #19. --- .../OpenTK/Platform/Windows/WinGLContext.cs | 217 ++++++++++-------- 1 file changed, 126 insertions(+), 91 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index 92c21851..9d4bf4c5 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -28,88 +28,111 @@ namespace OpenTK.Platform.Windows internal sealed class WinGLContext : DesktopGraphicsContext { static readonly object LoadLock = new object(); - static readonly object SyncRoot = new object(); bool vsync_supported; readonly WinGraphicsMode ModeSelector; - #region --- Contructors --- - - static WinGLContext() + // We need to create a temp context in order to load + // wgl extensions (e.g. for multisampling or GL3). + // We cannot rely on any WGL extensions before + // we load them with the temporary context. + class TemporaryContext : IDisposable { - lock (LoadLock) + public ContextHandle Context; + + public TemporaryContext(INativeWindow native) { - // We need to create a temp context in order to load - // wgl extensions (e.g. for multisampling or GL3). - // We cannot rely on OpenTK.Platform.Wgl until we - // create the context and call Wgl.LoadAll(). - Debug.Print("Creating temporary context for wgl extensions."); - using (INativeWindow native = new NativeWindow()) + Debug.WriteLine("[WGL] Creating temporary context to load extensions"); + + if (native == null) + throw new ArgumentNullException(); + + // Create temporary context and load WGL entry points + // First, set a compatible pixel format to the device context + // of the temp window + WinWindowInfo window = native.WindowInfo as WinWindowInfo; + WinGraphicsMode selector = new WinGraphicsMode(window.DeviceContext); + WinGLContext.SetGraphicsModePFD(selector, GraphicsMode.Default, window); + + bool success = false; + + // Then, construct a temporary context and load all wgl extensions + Context = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); + if (Context != ContextHandle.Zero) { - // Create temporary context and load WGL entry points - // First, set a compatible pixel format to the device context - // of the temp window - WinWindowInfo window = native.WindowInfo as WinWindowInfo; - WinGraphicsMode selector = new WinGraphicsMode(window.DeviceContext); - SetGraphicsModePFD(selector, GraphicsMode.Default, window); - - // Then, construct a temporary context and load all wgl extensions - ContextHandle temp_context = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); - if (temp_context != ContextHandle.Zero) + // Make the context current. + // Note: on some video cards and on some virtual machines, wglMakeCurrent + // may fail with an errorcode of 6 (INVALID_HANDLE). The suggested workaround + // is to call wglMakeCurrent in a loop until it succeeds. + // See https://www.opengl.org/discussion_boards/showthread.php/171058-nVidia-wglMakeCurrent()-multiple-threads + // Sigh... + for (int retry = 0; retry < 5 && !success; retry++) { - // Make the context current. - // Note: on some video cards and on some virtual machines, wglMakeCurrent - // may fail with an errorcode of 6 (INVALID_HANDLE). The suggested workaround - // is to call wglMakeCurrent in a loop until it succeeds. - // See https://www.opengl.org/discussion_boards/showthread.php/171058-nVidia-wglMakeCurrent()-multiple-threads - // Sigh... - for (int retry = 0; retry < 5; retry++) - { - bool success = Wgl.MakeCurrent(window.DeviceContext, temp_context.Handle); - if (!success) - { - Debug.Print("wglMakeCurrent failed with error: {0}. Retrying", Marshal.GetLastWin32Error()); - System.Threading.Thread.Sleep(10); - } - else - { - // wglMakeCurrent succeeded, we are done here! - break; - } - } + success = Wgl.MakeCurrent(window.DeviceContext, Context.Handle); + if (!success) + { + Debug.Print("wglMakeCurrent failed with error: {0}. Retrying", Marshal.GetLastWin32Error()); + System.Threading.Thread.Sleep(10); + } + } + } + else + { + Debug.Print("[WGL] CreateContext failed with error: {0}", Marshal.GetLastWin32Error()); + } - // Load wgl extensions and destroy temporary context - Wgl.LoadAll(); - Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero); - Wgl.DeleteContext(temp_context.Handle); - } - else - { - Debug.Print("wglCreateContext failed with error: {0}", Marshal.GetLastWin32Error()); - } + if (!success) + { + Debug.WriteLine("[WGL] Failed to create temporary context"); + } + } + + public void Dispose() + { + if (Context != ContextHandle.Zero) + { + Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero); + Wgl.DeleteContext(Context.Handle); } } } + #region --- Contructors --- + public WinGLContext(GraphicsMode format, WinWindowInfo window, IGraphicsContext sharedContext, int major, int minor, GraphicsContextFlags flags) { // There are many ways this code can break when accessed by multiple threads. The biggest offender is // the sharedContext stuff, which will only become valid *after* this constructor returns. // The easiest solution is to serialize all context construction - hence the big lock, below. - lock (SyncRoot) + lock (LoadLock) { if (window == null) throw new ArgumentNullException("window", "Must point to a valid window."); if (window.Handle == IntPtr.Zero) throw new ArgumentException("window", "Must be a valid window."); - Debug.Print("OpenGL will be bound to window:{0} on thread:{1}", window.Handle, - System.Threading.Thread.CurrentThread.ManagedThreadId); - - lock (LoadLock) + IntPtr current_context = Wgl.GetCurrentContext(); + INativeWindow temp_window = null; + TemporaryContext temp_context = null; + try { + if (current_context == IntPtr.Zero) + { + // Create temporary context to load WGL extensions + temp_window = new NativeWindow(); + temp_context = new TemporaryContext(temp_window); + current_context = Wgl.GetCurrentContext(); + if (current_context != IntPtr.Zero && current_context == temp_context.Context.Handle) + { + Wgl.LoadAll(); + } + } + + Debug.Print("OpenGL will be bound to window:{0} on thread:{1}", window.Handle, + System.Threading.Thread.CurrentThread.ManagedThreadId); + ModeSelector = new WinGraphicsMode(window.DeviceContext); Mode = SetGraphicsModePFD(ModeSelector, format, (WinWindowInfo)window); @@ -146,43 +169,56 @@ namespace OpenTK.Platform.Windows if (Handle == ContextHandle.Zero) Debug.Print("failed. (Error: {0})", Marshal.GetLastWin32Error()); } - catch (EntryPointNotFoundException e) { Debug.Print(e.ToString()); } - catch (NullReferenceException e) { Debug.Print(e.ToString()); } + catch (Exception e) { Debug.Print(e.ToString()); } + } + + if (Handle == ContextHandle.Zero) + { + // Failed to create GL3-level context, fall back to GL2. + Debug.Write("Falling back to GL2... "); + Handle = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); + if (Handle == ContextHandle.Zero) + Handle = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); + if (Handle == ContextHandle.Zero) + throw new GraphicsContextException( + String.Format("Context creation failed. Wgl.CreateContext() error: {0}.", + Marshal.GetLastWin32Error())); + } + + Debug.WriteLine(String.Format("success! (id: {0})", Handle)); + } + finally + { + if (temp_context != null) + { + temp_context.Dispose(); + temp_context = null; + } + if (temp_window != null) + { + temp_window.Dispose(); + temp_window = null; } } + } - if (Handle == ContextHandle.Zero) - { - // Failed to create GL3-level context, fall back to GL2. - Debug.Write("Falling back to GL2... "); - Handle = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); - if (Handle == ContextHandle.Zero) - Handle = new ContextHandle(Wgl.CreateContext(window.DeviceContext)); - if (Handle == ContextHandle.Zero) - throw new GraphicsContextException( - String.Format("Context creation failed. Wgl.CreateContext() error: {0}.", - Marshal.GetLastWin32Error())); - } + // Todo: is this comment still true? + // On intel drivers, wgl entry points appear to change + // when creating multiple contexts. As a workaround, + // we reload Wgl entry points every time we create a + // new context - this solves the issue without any apparent + // side-effects (i.e. the old contexts can still be handled + // using the new entry points.) + // Sigh... + Wgl.MakeCurrent(window.DeviceContext, Handle.Handle); + Wgl.LoadAll(); - Debug.WriteLine(String.Format("success! (id: {0})", Handle)); - - // Todo: is this comment still true? - // On intel drivers, wgl entry points appear to change - // when creating multiple contexts. As a workaround, - // we reload Wgl entry points every time we create a - // new context - this solves the issue without any apparent - // side-effects (i.e. the old contexts can still be handled - // using the new entry points.) - // Sigh... - Wgl.LoadAll(); - - if (sharedContext != null) - { - Marshal.GetLastWin32Error(); - Debug.Write(String.Format("Sharing state with context {0}: ", sharedContext)); - bool result = Wgl.ShareLists((sharedContext as IGraphicsContextInternal).Context.Handle, Handle.Handle); - Debug.WriteLine(result ? "success!" : "failed with win32 error " + Marshal.GetLastWin32Error()); - } + if (sharedContext != null) + { + Marshal.GetLastWin32Error(); + Debug.Write(String.Format("Sharing state with context {0}: ", sharedContext)); + bool result = Wgl.ShareLists((sharedContext as IGraphicsContextInternal).Context.Handle, Handle.Handle); + Debug.WriteLine(result ? "success!" : "failed with win32 error " + Marshal.GetLastWin32Error()); } } @@ -231,7 +267,6 @@ namespace OpenTK.Platform.Windows public override void MakeCurrent(IWindowInfo window) { - lock (SyncRoot) lock (LoadLock) { bool success; @@ -347,7 +382,7 @@ namespace OpenTK.Platform.Windows { // See https://www.opengl.org/wiki/Load_OpenGL_Functions long a = address.ToInt64(); - bool is_valid = (a < -1 )|| (a > 3); + bool is_valid = (a < -1) || (a > 3); return is_valid; } @@ -379,7 +414,7 @@ namespace OpenTK.Platform.Windows Functions.DescribePixelFormat( window.DeviceContext, (int)mode.Index.Value, API.PixelFormatDescriptorSize, ref pfd); - + Debug.WriteLine(mode.Index.ToString()); if (!Functions.SetPixelFormat(window.DeviceContext, (int)mode.Index.Value, ref pfd)) From b81aaf9a124d93e613c48236d60bbed78f5c0abb Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Wed, 18 Dec 2013 14:29:18 +0100 Subject: [PATCH 015/154] No point in using 16bpp color --- Source/Examples/OpenGL/1.x/ImmediateMode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Examples/OpenGL/1.x/ImmediateMode.cs b/Source/Examples/OpenGL/1.x/ImmediateMode.cs index ca31c83b..c44c2f5b 100644 --- a/Source/Examples/OpenGL/1.x/ImmediateMode.cs +++ b/Source/Examples/OpenGL/1.x/ImmediateMode.cs @@ -34,7 +34,7 @@ namespace Examples.Tutorial #region --- Constructor --- public T03_Immediate_Mode_Cube() - : base(800, 600, new GraphicsMode(16, 16)) + : base(800, 600) { } #endregion From ecd7db99c185295a9a4d7b1611ba46e65047068e Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Wed, 18 Dec 2013 14:51:00 +0100 Subject: [PATCH 016/154] Replace Wgl.GetCurrentDC with cached dc with --- Source/OpenTK/Platform/Windows/WinGLContext.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index 9d4bf4c5..0e727df7 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -29,6 +29,7 @@ namespace OpenTK.Platform.Windows { static readonly object LoadLock = new object(); + IntPtr device_context; bool vsync_supported; readonly WinGraphicsMode ModeSelector; @@ -210,7 +211,7 @@ namespace OpenTK.Platform.Windows // side-effects (i.e. the old contexts can still be handled // using the new entry points.) // Sigh... - Wgl.MakeCurrent(window.DeviceContext, Handle.Handle); + MakeCurrent(window); Wgl.LoadAll(); if (sharedContext != null) @@ -284,9 +285,13 @@ namespace OpenTK.Platform.Windows success = Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero); } + device_context = wnd.DeviceContext; + if (!success) + { throw new GraphicsContextException(String.Format( "Failed to make context {0} current. Error: {1}", this, Marshal.GetLastWin32Error())); + } } } @@ -435,11 +440,10 @@ namespace OpenTK.Platform.Windows { get { - return Wgl.GetCurrentDC(); + return device_context; } } - #endregion #endregion From 6493ab018838678c27b9dd81435ae021772e6259 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Thu, 19 Dec 2013 10:39:36 +0100 Subject: [PATCH 017/154] Threads with message pump require STA comparment May affect issue #19 --- Source/OpenTK/Platform/Windows/WinInputBase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/OpenTK/Platform/Windows/WinInputBase.cs b/Source/OpenTK/Platform/Windows/WinInputBase.cs index 44d82ee7..252a6f8d 100644 --- a/Source/OpenTK/Platform/Windows/WinInputBase.cs +++ b/Source/OpenTK/Platform/Windows/WinInputBase.cs @@ -58,6 +58,7 @@ namespace OpenTK.Platform.Windows WndProc = WindowProcedure; InputThread = new Thread(ProcessEvents); + InputThread.SetApartmentState(ApartmentState.STA); InputThread.IsBackground = true; InputThread.Start(); From 1edfa8f3dec4472d5bdf7c2a2b6b3777c09f835d Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Fri, 20 Dec 2013 08:42:36 +0100 Subject: [PATCH 018/154] Simplify ProcessEvents implementation Instead of combining PeekMessage+GetMessage, we can simply call PeekMessage(Remove) to achieve the same effect. This also allows us to remove the IsIdle property, which is no longer used anywhere. --- Source/OpenTK/Platform/Windows/API.cs | 14 ++++++++++- Source/OpenTK/Platform/Windows/WinGLNative.cs | 24 +------------------ 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/API.cs b/Source/OpenTK/Platform/Windows/API.cs index b9107d7a..c05398e0 100644 --- a/Source/OpenTK/Platform/Windows/API.cs +++ b/Source/OpenTK/Platform/Windows/API.cs @@ -349,7 +349,7 @@ namespace OpenTK.Platform.Windows [System.Security.SuppressUnmanagedCodeSecurity] [DllImport("User32.dll"), CLSCompliant(false)] [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool PeekMessage(ref MSG msg, IntPtr hWnd, int messageFilterMin, int messageFilterMax, int flags); + internal static extern bool PeekMessage(ref MSG msg, IntPtr hWnd, int messageFilterMin, int messageFilterMax, PeekMessageFlags flags); #endregion @@ -4028,6 +4028,18 @@ namespace OpenTK.Platform.Windows #endregion + #region PeekMessageFlags + + [Flags] + enum PeekMessageFlags : uint + { + NoRemove = 0, + Remove = 1, + NoYield = 2 + } + + #endregion + #region ShowWindowCommand /// diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index aae5d109..ccdcbd39 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -583,19 +583,6 @@ namespace OpenTK.Platform.Windows #endregion - #region IsIdle - - bool IsIdle - { - get - { - MSG message = new MSG(); - return !Functions.PeekMessage(ref message, window.Handle, 0, 0, 0); - } - } - - #endregion - #region CreateWindow IntPtr CreateWindow(int x, int y, int width, int height, string title, GameWindowFlags options, DisplayDevice device, IntPtr parentHandle) @@ -1217,20 +1204,11 @@ namespace OpenTK.Platform.Windows #region public void ProcessEvents() - private int ret; MSG msg; public void ProcessEvents() { - while (!IsIdle) + while (Functions.PeekMessage(ref msg, window.Handle, 0, 0, PeekMessageFlags.Remove)) { - ret = Functions.GetMessage(ref msg, window.Handle, 0, 0); - if (ret == -1) - { - throw new PlatformException(String.Format( - "An error happened while processing the message queue. Windows error: {0}", - Marshal.GetLastWin32Error())); - } - Functions.TranslateMessage(ref msg); Functions.DispatchMessage(ref msg); } From 6696bef3eb45b41317d3e6716898c8db99620130 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Fri, 20 Dec 2013 23:29:47 +0100 Subject: [PATCH 019/154] Explicitly set WindowProcedure calling convention --- Source/OpenTK/Platform/Windows/API.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/OpenTK/Platform/Windows/API.cs b/Source/OpenTK/Platform/Windows/API.cs index c05398e0..316a85ae 100644 --- a/Source/OpenTK/Platform/Windows/API.cs +++ b/Source/OpenTK/Platform/Windows/API.cs @@ -4313,6 +4313,8 @@ namespace OpenTK.Platform.Windows #region --- Callbacks --- + [SuppressUnmanagedCodeSecurity] + [UnmanagedFunctionPointer(CallingConvention.Winapi)] internal delegate IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam); #region Message From d877061d6a52c6b1b0bee4ef7192b4223f9d2985 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Fri, 20 Dec 2013 23:31:42 +0100 Subject: [PATCH 020/154] Fix issue #19 Don't filter window messages passed to our window (see http://blogs.msdn.com/b/oldnewthing/archive/2005/02/09/369804.aspx). Additionally, return the correct values for all messages we are actually handling and clean up unmanaged memory after we are done with the window. --- Source/OpenTK/Platform/Windows/WinGLNative.cs | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index ccdcbd39..d2134aae 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -257,7 +257,7 @@ namespace OpenTK.Platform.Windows if (new_focused_state != Focused) FocusedChanged(this, EventArgs.Empty); - break; + return IntPtr.Zero; case WindowMessage.ENTERMENULOOP: case WindowMessage.ENTERSIZEMOVE: @@ -269,7 +269,7 @@ namespace OpenTK.Platform.Windows if (!CursorVisible) UngrabCursor(); - break; + return IntPtr.Zero; case WindowMessage.EXITMENULOOP: case WindowMessage.EXITSIZEMOVE: @@ -327,7 +327,7 @@ namespace OpenTK.Platform.Windows } } } - break; + return IntPtr.Zero; case WindowMessage.STYLECHANGED: unsafe @@ -347,8 +347,8 @@ namespace OpenTK.Platform.Windows // Ensure cursor remains grabbed if (!CursorVisible) GrabCursor(); - - break; + + return IntPtr.Zero; case WindowMessage.SIZE: SizeMessage state = (SizeMessage)wParam.ToInt64(); @@ -373,7 +373,7 @@ namespace OpenTK.Platform.Windows GrabCursor(); } - break; + return IntPtr.Zero; #endregion @@ -386,7 +386,7 @@ namespace OpenTK.Platform.Windows key_press.KeyChar = (char)wParam.ToInt64(); KeyPress(this, key_press); - break; + return IntPtr.Zero; case WindowMessage.MOUSEMOVE: Point point = new Point( @@ -403,62 +403,62 @@ namespace OpenTK.Platform.Windows MouseEnter(this, EventArgs.Empty); } - break; + return IntPtr.Zero; case WindowMessage.MOUSELEAVE: mouse_outside_window = true; // Mouse tracking is disabled automatically by the OS MouseLeave(this, EventArgs.Empty); - break; + return IntPtr.Zero; case WindowMessage.MOUSEWHEEL: // This is due to inconsistent behavior of the WParam value on 64bit arch, whese // wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000 mouse.WheelPrecise += ((long)wParam << 32 >> 48) / 120.0f; - break; + return IntPtr.Zero; case WindowMessage.LBUTTONDOWN: Functions.SetCapture(window.Handle); mouse[MouseButton.Left] = true; - break; + return IntPtr.Zero; case WindowMessage.MBUTTONDOWN: Functions.SetCapture(window.Handle); mouse[MouseButton.Middle] = true; - break; + return IntPtr.Zero; case WindowMessage.RBUTTONDOWN: Functions.SetCapture(window.Handle); mouse[MouseButton.Right] = true; - break; + return IntPtr.Zero; case WindowMessage.XBUTTONDOWN: Functions.SetCapture(window.Handle); mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) != (int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = true; - break; + return IntPtr.Zero; case WindowMessage.LBUTTONUP: Functions.ReleaseCapture(); mouse[MouseButton.Left] = false; - break; + return IntPtr.Zero; case WindowMessage.MBUTTONUP: Functions.ReleaseCapture(); mouse[MouseButton.Middle] = false; - break; + return IntPtr.Zero; case WindowMessage.RBUTTONUP: Functions.ReleaseCapture(); mouse[MouseButton.Right] = false; - break; + return IntPtr.Zero; case WindowMessage.XBUTTONUP: Functions.ReleaseCapture(); mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) != (int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = false; - break; + return IntPtr.Zero; // Keyboard events: case WindowMessage.KEYDOWN: @@ -494,7 +494,7 @@ namespace OpenTK.Platform.Windows case WindowMessage.KILLFOCUS: keyboard.ClearKeys(); - break; + return IntPtr.Zero; #endregion @@ -515,7 +515,7 @@ namespace OpenTK.Platform.Windows invisible_since_creation = true; } - break; + return IntPtr.Zero; case WindowMessage.CLOSE: System.ComponentModel.CancelEventArgs e = new System.ComponentModel.CancelEventArgs(); @@ -532,18 +532,16 @@ namespace OpenTK.Platform.Windows case WindowMessage.DESTROY: exists = false; - - Functions.UnregisterClass(ClassName, Instance); - window.Dispose(); - child_window.Dispose(); - Closed(this, EventArgs.Empty); + return IntPtr.Zero; + case WindowMessage.GETICON: break; #endregion } + Debug.Print(message.ToString()); return Functions.DefWindowProc(handle, message, wParam, lParam); } @@ -854,8 +852,8 @@ namespace OpenTK.Platform.Windows icon = value; if (window.Handle != IntPtr.Zero) { - Functions.SendMessage(window.Handle, WindowMessage.SETICON, (IntPtr)0, icon == null ? IntPtr.Zero : value.Handle); - Functions.SendMessage(window.Handle, WindowMessage.SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle); + Functions.PostMessage(window.Handle, WindowMessage.SETICON, (IntPtr)0, icon == null ? IntPtr.Zero : value.Handle); + Functions.PostMessage(window.Handle, WindowMessage.SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle); } IconChanged(this, EventArgs.Empty); } @@ -1207,7 +1205,7 @@ namespace OpenTK.Platform.Windows MSG msg; public void ProcessEvents() { - while (Functions.PeekMessage(ref msg, window.Handle, 0, 0, PeekMessageFlags.Remove)) + while (Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, PeekMessageFlags.Remove)) { Functions.TranslateMessage(ref msg); Functions.DispatchMessage(ref msg); @@ -1298,8 +1296,14 @@ namespace OpenTK.Platform.Windows { // Safe to clean managed resources DestroyWindow(); + Functions.UnregisterClass(ClassName, Instance); + window.Dispose(); + child_window.Dispose(); + if (Icon != null) Icon.Dispose(); + if (ClassName != IntPtr.Zero) + Marshal.FreeHGlobal(ClassName); } else { From 1e4228456f5c5f284b4c111e2bb3fa97c0a423b6 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sat, 21 Dec 2013 00:41:55 +0100 Subject: [PATCH 021/154] Revert "Fix issue #19" This reverts commit 2c14ec5f800b8ef6527f05ba26d6c6cca4b417d8. --- Source/OpenTK/Platform/Windows/WinGLNative.cs | 62 +++++++++---------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index d2134aae..ccdcbd39 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -257,7 +257,7 @@ namespace OpenTK.Platform.Windows if (new_focused_state != Focused) FocusedChanged(this, EventArgs.Empty); - return IntPtr.Zero; + break; case WindowMessage.ENTERMENULOOP: case WindowMessage.ENTERSIZEMOVE: @@ -269,7 +269,7 @@ namespace OpenTK.Platform.Windows if (!CursorVisible) UngrabCursor(); - return IntPtr.Zero; + break; case WindowMessage.EXITMENULOOP: case WindowMessage.EXITSIZEMOVE: @@ -327,7 +327,7 @@ namespace OpenTK.Platform.Windows } } } - return IntPtr.Zero; + break; case WindowMessage.STYLECHANGED: unsafe @@ -347,8 +347,8 @@ namespace OpenTK.Platform.Windows // Ensure cursor remains grabbed if (!CursorVisible) GrabCursor(); - - return IntPtr.Zero; + + break; case WindowMessage.SIZE: SizeMessage state = (SizeMessage)wParam.ToInt64(); @@ -373,7 +373,7 @@ namespace OpenTK.Platform.Windows GrabCursor(); } - return IntPtr.Zero; + break; #endregion @@ -386,7 +386,7 @@ namespace OpenTK.Platform.Windows key_press.KeyChar = (char)wParam.ToInt64(); KeyPress(this, key_press); - return IntPtr.Zero; + break; case WindowMessage.MOUSEMOVE: Point point = new Point( @@ -403,62 +403,62 @@ namespace OpenTK.Platform.Windows MouseEnter(this, EventArgs.Empty); } - return IntPtr.Zero; + break; case WindowMessage.MOUSELEAVE: mouse_outside_window = true; // Mouse tracking is disabled automatically by the OS MouseLeave(this, EventArgs.Empty); - return IntPtr.Zero; + break; case WindowMessage.MOUSEWHEEL: // This is due to inconsistent behavior of the WParam value on 64bit arch, whese // wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000 mouse.WheelPrecise += ((long)wParam << 32 >> 48) / 120.0f; - return IntPtr.Zero; + break; case WindowMessage.LBUTTONDOWN: Functions.SetCapture(window.Handle); mouse[MouseButton.Left] = true; - return IntPtr.Zero; + break; case WindowMessage.MBUTTONDOWN: Functions.SetCapture(window.Handle); mouse[MouseButton.Middle] = true; - return IntPtr.Zero; + break; case WindowMessage.RBUTTONDOWN: Functions.SetCapture(window.Handle); mouse[MouseButton.Right] = true; - return IntPtr.Zero; + break; case WindowMessage.XBUTTONDOWN: Functions.SetCapture(window.Handle); mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) != (int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = true; - return IntPtr.Zero; + break; case WindowMessage.LBUTTONUP: Functions.ReleaseCapture(); mouse[MouseButton.Left] = false; - return IntPtr.Zero; + break; case WindowMessage.MBUTTONUP: Functions.ReleaseCapture(); mouse[MouseButton.Middle] = false; - return IntPtr.Zero; + break; case WindowMessage.RBUTTONUP: Functions.ReleaseCapture(); mouse[MouseButton.Right] = false; - return IntPtr.Zero; + break; case WindowMessage.XBUTTONUP: Functions.ReleaseCapture(); mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) != (int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = false; - return IntPtr.Zero; + break; // Keyboard events: case WindowMessage.KEYDOWN: @@ -494,7 +494,7 @@ namespace OpenTK.Platform.Windows case WindowMessage.KILLFOCUS: keyboard.ClearKeys(); - return IntPtr.Zero; + break; #endregion @@ -515,7 +515,7 @@ namespace OpenTK.Platform.Windows invisible_since_creation = true; } - return IntPtr.Zero; + break; case WindowMessage.CLOSE: System.ComponentModel.CancelEventArgs e = new System.ComponentModel.CancelEventArgs(); @@ -532,16 +532,18 @@ namespace OpenTK.Platform.Windows case WindowMessage.DESTROY: exists = false; - Closed(this, EventArgs.Empty); - return IntPtr.Zero; - case WindowMessage.GETICON: + Functions.UnregisterClass(ClassName, Instance); + window.Dispose(); + child_window.Dispose(); + + Closed(this, EventArgs.Empty); + break; #endregion } - Debug.Print(message.ToString()); return Functions.DefWindowProc(handle, message, wParam, lParam); } @@ -852,8 +854,8 @@ namespace OpenTK.Platform.Windows icon = value; if (window.Handle != IntPtr.Zero) { - Functions.PostMessage(window.Handle, WindowMessage.SETICON, (IntPtr)0, icon == null ? IntPtr.Zero : value.Handle); - Functions.PostMessage(window.Handle, WindowMessage.SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle); + Functions.SendMessage(window.Handle, WindowMessage.SETICON, (IntPtr)0, icon == null ? IntPtr.Zero : value.Handle); + Functions.SendMessage(window.Handle, WindowMessage.SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle); } IconChanged(this, EventArgs.Empty); } @@ -1205,7 +1207,7 @@ namespace OpenTK.Platform.Windows MSG msg; public void ProcessEvents() { - while (Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, PeekMessageFlags.Remove)) + while (Functions.PeekMessage(ref msg, window.Handle, 0, 0, PeekMessageFlags.Remove)) { Functions.TranslateMessage(ref msg); Functions.DispatchMessage(ref msg); @@ -1296,14 +1298,8 @@ namespace OpenTK.Platform.Windows { // Safe to clean managed resources DestroyWindow(); - Functions.UnregisterClass(ClassName, Instance); - window.Dispose(); - child_window.Dispose(); - if (Icon != null) Icon.Dispose(); - if (ClassName != IntPtr.Zero) - Marshal.FreeHGlobal(ClassName); } else { From 6dc474f59581e3560ede7975f347610beadf4202 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sat, 21 Dec 2013 00:43:05 +0100 Subject: [PATCH 022/154] Clean fix issue #19 Isolate and commit fix for issue #19 without potential for regressions. --- Source/OpenTK/Platform/Windows/WinGLNative.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index ccdcbd39..6125ffd3 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -1207,7 +1207,7 @@ namespace OpenTK.Platform.Windows MSG msg; public void ProcessEvents() { - while (Functions.PeekMessage(ref msg, window.Handle, 0, 0, PeekMessageFlags.Remove)) + while (Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, PeekMessageFlags.Remove)) { Functions.TranslateMessage(ref msg); Functions.DispatchMessage(ref msg); From 8b1566b24458395bd194c29a981c29a3d63f2d26 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sat, 21 Dec 2013 00:50:25 +0100 Subject: [PATCH 023/154] Implemented KeyDown and KeyUp messages --- Source/OpenTK/Platform/Windows/WinGLNative.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index 6125ffd3..48f7c4b1 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -98,6 +98,8 @@ namespace OpenTK.Platform.Windows public static readonly uint AltLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LMENU, 0); public static readonly uint AltRightScanCode = Functions.MapVirtualKey(VirtualKeys.RMENU, 0); + KeyboardKeyEventArgs key_down = new KeyboardKeyEventArgs(); + KeyboardKeyEventArgs key_up = new KeyboardKeyEventArgs(); KeyPressEventArgs key_press = new KeyPressEventArgs((char)0); int cursor_visible_count = 0; @@ -485,6 +487,18 @@ namespace OpenTK.Platform.Windows if (is_valid) { keyboard.SetKey(key, (byte)scancode, pressed); + + if (pressed) + { + key_down.Key = key; + KeyDown(this, key_down); + } + else + { + key_up.Key = key; + KeyUp(this, key_up); + } + } return IntPtr.Zero; From 98600b00085d13d7d9628b4c630601201763b4fa Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sat, 21 Dec 2013 22:41:10 +0100 Subject: [PATCH 024/154] Display renderer information --- Source/Examples/OpenTK/Test/GameWindowStates.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 73d81002..cdb5afa2 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -218,7 +218,10 @@ namespace Examples.Tests gfx.Clear(Color.Black); gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; - + + DrawString(gfx, GL.GetString(StringName.Vendor), line++); + DrawString(gfx, GL.GetString(StringName.Version), line++); + DrawString(gfx, GL.GetString(StringName.Renderer), line++); DrawString(gfx, Context.GraphicsMode.ToString(), line++); DrawString(gfx, String.Format("[1 - 4]: change WindowState (current: {0}).", this.WindowState), line++); From 030cf937a0d397bebc751bc59972b76155fac33b Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sat, 21 Dec 2013 22:41:35 +0100 Subject: [PATCH 025/154] Turn 1-element array to ref/out param --- Source/OpenTK/Platform/Windows/Bindings/Wgl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs b/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs index e235beb8..e1bd92ad 100644 --- a/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs +++ b/Source/OpenTK/Platform/Windows/Bindings/Wgl.cs @@ -202,14 +202,14 @@ namespace OpenTK.Platform.Windows } public static - Boolean ChoosePixelFormat(IntPtr hdc, int[] piAttribIList, Single[] pfAttribFList, Int32 nMaxFormats, [Out] int[] piFormats, [Out] Int32[] nNumFormats) + Boolean ChoosePixelFormat(IntPtr hdc, int[] piAttribIList, Single[] pfAttribFList, Int32 nMaxFormats, [Out] int[] piFormats, out int nNumFormats) { unsafe { fixed (int* piAttribIList_ptr = piAttribIList) fixed (Single* pfAttribFList_ptr = pfAttribFList) fixed (int* piFormats_ptr = piFormats) - fixed (Int32* nNumFormats_ptr = nNumFormats) + fixed (Int32* nNumFormats_ptr = &nNumFormats) { return Delegates.wglChoosePixelFormatARB((IntPtr)hdc, (int*)piAttribIList_ptr, (Single*)pfAttribFList_ptr, (UInt32)nMaxFormats, (int*)piFormats_ptr, (UInt32*)nNumFormats_ptr); } From 0ad87bec3dd9c8bff1712487dba226ae9ae895bf Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sat, 21 Dec 2013 22:43:35 +0100 Subject: [PATCH 026/154] Prioritize accelerated formats first Instead of creating a list of all available formats and iterating through that, we let the driver decide which is the best accelerated format to use for the user parameters. If no such format exists, we fall back to generic acceleration or software acceleration, in turn. This affects issue #21 --- .../Platform/Windows/WinGraphicsMode.cs | 410 +++++++++++------- 1 file changed, 250 insertions(+), 160 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index 0efc07ce..e7cf613e 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -37,27 +37,28 @@ namespace OpenTK.Platform.Windows { class WinGraphicsMode : IGraphicsMode { - #region Fields + enum AccelerationType + { + // Software acceleration + None = 0, + // Partial acceleration (Direct3D emulation) + MCD, + // Full acceleration + ICD, + } - readonly List modes = new List(); static readonly object SyncRoot = new object(); - - #endregion + readonly IntPtr Device; + readonly List modes = new List(); #region Constructors public WinGraphicsMode(IntPtr device) { - lock (SyncRoot) - { - modes.AddRange(GetModesARB(device)); - if (modes.Count == 0) - modes.AddRange(GetModesPFD(device)); - if (modes.Count == 0) - throw new GraphicsModeException( - "No GraphicsMode available. This should never happen, please report a bug at http://www.opentk.com"); - modes.Sort(new GraphicsModeComparer()); - } + if (device == IntPtr.Zero) + throw new ArgumentException(); + + Device = device; } #endregion @@ -67,57 +68,172 @@ namespace OpenTK.Platform.Windows public GraphicsMode SelectGraphicsMode(ColorFormat color, int depth, int stencil, int samples, ColorFormat accum, int buffers, bool stereo) { - GraphicsMode mode = null; - do + GraphicsMode mode = new GraphicsMode(color, depth, stencil, samples,accum, buffers, stereo); + GraphicsMode created_mode = ChoosePixelFormatARB(Device, mode); + + // If ChoosePixelFormatARB failed, iterate through all acceleration types in turn (ICD, MCD, None) + // This should fix issue #2224, which causes OpenTK to fail on VMs without hardware acceleration. + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.ICD); + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.MCD); + created_mode = created_mode ?? ChoosePixelFormatPFD(Device, mode, AccelerationType.None); + + if (created_mode == null) { - mode = modes.Find(delegate(GraphicsMode current) - { - return ModeSelector(current, color, depth, stencil, samples, accum, buffers, stereo); - }); - } while (mode == null && RelaxParameters( - ref color, ref depth, ref stencil, ref samples, ref accum, ref buffers, ref stereo)); + throw new GraphicsModeException("The requested GraphicsMode is not supported"); + } - if (mode == null) - mode = modes[0]; - - return mode; - } - - bool RelaxParameters(ref ColorFormat color, ref int depth, ref int stencil, ref int samples, - ref ColorFormat accum, ref int buffers, ref bool stereo) - { - if (stereo) { stereo = false; return true; } - if (buffers != 2) { buffers = 2; return true; } - if (accum != 0) { accum = 0; return true; } - if (samples != 0) { samples = 0; return true; } - if (depth < 16) { depth = 16; return true; } - if (depth != 24) { depth = 24; return true; } - if (stencil > 0 && stencil != 8) { stencil = 8; return true; } - if (stencil == 8) { stencil = 0; return true; } - if (color < 8) { color = 8; return true; } - if (color < 16) { color = 16; return true; } - if (color < 24) { color = 24; return true; } - if (color < 32 || color > 32) { color = 32; return true; } - return false; // We tried everything we could, no match found. + return created_mode; } #endregion #region Private Methods - #region GetModesPFD + #region ChoosePixelFormatARB - IEnumerable GetModesPFD(IntPtr device) + // Queries pixel formats through the WGL_ARB_pixel_format extension + // This method only returns accelerated formats. If no format offers + // hardware acceleration (e.g. we are running in a VM or in a remote desktop + // connection), this method will return 0 formats and we will fall back to + // ChoosePixelFormatPFD. + GraphicsMode ChoosePixelFormatARB(IntPtr device, GraphicsMode mode) { - Debug.WriteLine(String.Format("Device context: {0}", device)); + GraphicsMode created_mode = null; + if (Wgl.Delegates.wglChoosePixelFormatARB != null) + { + List attributes = new List(); + attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); + attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); - Debug.WriteLine("Retrieving PFD pixel formats... "); + if (mode.ColorFormat.BitsPerPixel > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.RedBitsArb); + attributes.Add(mode.ColorFormat.Red); + attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb); + attributes.Add(mode.ColorFormat.Green); + attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb); + attributes.Add(mode.ColorFormat.Blue); + attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb); + attributes.Add(mode.ColorFormat.Alpha); + attributes.Add((int)WGL_ARB_pixel_format.ColorBitsArb); + attributes.Add(mode.ColorFormat.BitsPerPixel); + } + + if (mode.Depth > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.DepthBitsArb); + attributes.Add(mode.Depth); + } + + if (mode.Stencil > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.StencilBitsArb); + attributes.Add(mode.Stencil); + } + + if (mode.AccumulatorFormat.BitsPerPixel > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb); + attributes.Add(mode.AccumulatorFormat.Red); + attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb); + attributes.Add(mode.AccumulatorFormat.Green); + attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb); + attributes.Add(mode.AccumulatorFormat.Blue); + attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb); + attributes.Add(mode.AccumulatorFormat.Alpha); + attributes.Add((int)WGL_ARB_pixel_format.AccumBitsArb); + attributes.Add(mode.AccumulatorFormat.BitsPerPixel); + } + + if (mode.Samples > 0) + { + attributes.Add((int)WGL_ARB_multisample.SampleBuffersArb); + attributes.Add(1); + attributes.Add((int)WGL_ARB_multisample.SamplesArb); + attributes.Add(mode.Samples); + } + + if (mode.Buffers > 0) + { + attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb); + attributes.Add(mode.Buffers); + } + + if (mode.Stereo) + { + attributes.Add((int)WGL_ARB_pixel_format.StereoArb); + attributes.Add(1); + } + + attributes.Add(0); + attributes.Add(0); + + int[] format = new int[1]; + int count; + if (Wgl.Arb.ChoosePixelFormat(device, attributes.ToArray(), null, format.Length, format, out count)) + { + created_mode = DescribePixelFormatARB(device, format[0]); + } + else + { + Debug.Print("[WGL] ChoosePixelFormatARB failed with {0}", Marshal.GetLastWin32Error()); + } + } + else + { + Debug.Print("[WGL] ChoosePixelFormatARB not supported"); + } + + return created_mode; + } + + #endregion + + #region ChoosePixelFormatPFD + + GraphicsMode ChoosePixelFormatPFD(IntPtr Device, GraphicsMode mode, AccelerationType requested_acceleration_type) + { PixelFormatDescriptor pfd = new PixelFormatDescriptor(); - pfd.Size = API.PixelFormatDescriptorSize; - pfd.Version = API.PixelFormatDescriptorVersion; - pfd.Flags = - PixelFormatDescriptorFlags.SUPPORT_OPENGL | - PixelFormatDescriptorFlags.DRAW_TO_WINDOW; + pfd.Size = (short)BlittableValueType.Stride; + + if (mode.ColorFormat.BitsPerPixel > 0) + { + pfd.RedBits = (byte)mode.ColorFormat.Red; + pfd.GreenBits = (byte)mode.ColorFormat.Green; + pfd.BlueBits = (byte)mode.ColorFormat.Blue; + pfd.AlphaBits = (byte)mode.ColorFormat.Alpha; + pfd.ColorBits = (byte)mode.ColorFormat.BitsPerPixel; + } + + if (mode.Depth > 0) + { + pfd.DepthBits = (byte)mode.Depth; + } + + if (mode.Stencil > 0) + { + pfd.StencilBits = (byte)mode.Stencil; + } + + if (mode.AccumulatorFormat.BitsPerPixel > 0) + { + pfd.AccumRedBits = (byte)mode.AccumulatorFormat.Red; + pfd.AccumGreenBits = (byte)mode.AccumulatorFormat.Green; + pfd.AccumBlueBits = (byte)mode.AccumulatorFormat.Blue; + pfd.AccumAlphaBits = (byte)mode.AccumulatorFormat.Alpha; + pfd.AccumBits = (byte)mode.AccumulatorFormat.BitsPerPixel; + } + + if (mode.Buffers > 0) + { + pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; + } + + if (mode.Stereo) + { + pfd.Flags |= PixelFormatDescriptorFlags.DRAW_TO_WINDOW; + pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_OPENGL; + } // Make sure we don't turn off Aero on Vista and newer. if (Environment.OSVersion.Version.Major >= 6) @@ -125,109 +241,102 @@ namespace OpenTK.Platform.Windows pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION; } - foreach (bool generic_allowed in new bool[] { false, true }) + GraphicsMode created_mode = null; + int pixelformat = Functions.ChoosePixelFormat(Device, ref pfd); + if (pixelformat > 0) { - // Iterate through all accelerated formats first. Afterwards, iterate through non-accelerated formats. - // This should fix issue #2224, which causes OpenTK to fail on VMs without hardware acceleration. - // Note: DescribePixelFormat found in gdi32 is extremely slow on nvidia, for some reason. - int pixel = 0; - while (Functions.DescribePixelFormat(device, ++pixel, API.PixelFormatDescriptorSize, ref pfd) != 0) + AccelerationType acceleration_type = AccelerationType.ICD; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) { - // Ignore non-accelerated formats. - if (!generic_allowed && (pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) - continue; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0) + { + acceleration_type = AccelerationType.MCD; + } + else + { + acceleration_type = AccelerationType.None; + } + } - GraphicsMode fmt = new GraphicsMode((IntPtr)pixel, - new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), - pfd.DepthBits, - pfd.StencilBits, - 0, - new ColorFormat(pfd.AccumBits), - (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, - (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); - - yield return fmt; + if (acceleration_type == requested_acceleration_type) + { + created_mode = DescribePixelFormatPFD(ref pfd, pixelformat); } } + return created_mode; } #endregion - #region GetModesARB + #region DescribePixelFormatPFD - // Queries pixel formats through the WGL_ARB_pixel_format extension - // This method only returns accelerated formats. If no format offers - // hardware acceleration (e.g. we are running in a VM or in a remote desktop - // connection), this method will return 0 formats and we will fall back to - // GetModesPFD. - IEnumerable GetModesARB(IntPtr device) + static GraphicsMode DescribePixelFormatPFD(ref PixelFormatDescriptor pfd, int pixelformat) { - // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt - // for more details - Debug.Write("Retrieving ARB pixel formats.... "); - if (Wgl.Delegates.wglChoosePixelFormatARB == null || Wgl.Delegates.wglGetPixelFormatAttribivARB == null) + return new GraphicsMode( + new IntPtr(pixelformat), + new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), + pfd.DepthBits, + pfd.StencilBits, + 0, // MSAA not supported + new ColorFormat(pfd.AccumRedBits, pfd.AccumGreenBits, pfd.AccumBlueBits, pfd.AccumAlphaBits), + (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, + (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); + } + + #endregion + + #region DescribePixelFormatARB + + GraphicsMode DescribePixelFormatARB(IntPtr device, int pixelformat) + { + GraphicsMode created_mode = null; + // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt for more details + if (Wgl.Delegates.wglGetPixelFormatAttribivARB != null) { - Debug.WriteLine("failed."); - yield break; - } - - // Define the list of attributes we are interested in. - // We will use each available pixel format for these - // attributes using GetPixelFormatAttrib. - // The results will be stored in the 'values' array below. - int[] attribs = new int[] - { - (int)WGL_ARB_pixel_format.AccelerationArb, - - (int)WGL_ARB_pixel_format.RedBitsArb, - (int)WGL_ARB_pixel_format.GreenBitsArb, - (int)WGL_ARB_pixel_format.BlueBitsArb, - (int)WGL_ARB_pixel_format.AlphaBitsArb, - (int)WGL_ARB_pixel_format.ColorBitsArb, - - (int)WGL_ARB_pixel_format.DepthBitsArb, - (int)WGL_ARB_pixel_format.StencilBitsArb, - - (int)WGL_ARB_multisample.SampleBuffersArb, - (int)WGL_ARB_multisample.SamplesArb, - - (int)WGL_ARB_pixel_format.AccumRedBitsArb, - (int)WGL_ARB_pixel_format.AccumGreenBitsArb, - (int)WGL_ARB_pixel_format.AccumBlueBitsArb, - (int)WGL_ARB_pixel_format.AccumAlphaBitsArb, - (int)WGL_ARB_pixel_format.AccumBitsArb, - - (int)WGL_ARB_pixel_format.DoubleBufferArb, - (int)WGL_ARB_pixel_format.StereoArb, - 0 - }; - - // Allocate storage for the results of GetPixelFormatAttrib queries - int[] values = new int[attribs.Length]; - - // Get the number of available formats - int num_formats; - int num_formats_attrib = (int)WGL_ARB_pixel_format.NumberPixelFormatsArb; - if (Wgl.Arb.GetPixelFormatAttrib(device, 0, 0, 1, ref num_formats_attrib, out num_formats)) - { - for (int p = 1; p < num_formats; p++) + // Define the list of attributes we are interested in. + // The results will be stored in the 'values' array below. + int[] attribs = new int[] { - // Get the format attributes for this pixel format - if (!Wgl.Arb.GetPixelFormatAttrib(device, p, 0, attribs.Length - 1, attribs, values)) - { - Debug.Print("[Warning] Failed to detect attributes for PixelFormat:{0}.", p); - continue; - } + (int)WGL_ARB_pixel_format.AccelerationArb, - // Skip formats that don't offer full hardware acceleration - WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)attribs[0]; - if (acceleration != WGL_ARB_pixel_format.FullAccelerationArb) - { - continue; - } + (int)WGL_ARB_pixel_format.RedBitsArb, + (int)WGL_ARB_pixel_format.GreenBitsArb, + (int)WGL_ARB_pixel_format.BlueBitsArb, + (int)WGL_ARB_pixel_format.AlphaBitsArb, + (int)WGL_ARB_pixel_format.ColorBitsArb, + + (int)WGL_ARB_pixel_format.DepthBitsArb, + (int)WGL_ARB_pixel_format.StencilBitsArb, + + (int)WGL_ARB_multisample.SampleBuffersArb, + (int)WGL_ARB_multisample.SamplesArb, + (int)WGL_ARB_pixel_format.AccumRedBitsArb, + (int)WGL_ARB_pixel_format.AccumGreenBitsArb, + (int)WGL_ARB_pixel_format.AccumBlueBitsArb, + (int)WGL_ARB_pixel_format.AccumAlphaBitsArb, + (int)WGL_ARB_pixel_format.AccumBitsArb, + + (int)WGL_ARB_pixel_format.DoubleBufferArb, + (int)WGL_ARB_pixel_format.StereoArb, + 0 + }; + + // Allocate storage for the results of GetPixelFormatAttrib queries + int[] values = new int[attribs.Length]; + + // Get the format attributes for this pixel format + if (!Wgl.Arb.GetPixelFormatAttrib(device, pixelformat, 0, attribs.Length - 1, attribs, values)) + { + Debug.Print("[Warning] Failed to detect attributes for PixelFormat: {0}.", pixelformat); + } + + // Skip formats that don't offer full hardware acceleration + WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)attribs[0]; + if (acceleration == WGL_ARB_pixel_format.FullAccelerationArb) + { // Construct a new GraphicsMode to describe this format - GraphicsMode mode = new GraphicsMode(new IntPtr(p), + created_mode = new GraphicsMode(new IntPtr(pixelformat), new ColorFormat(values[1], values[2], values[3], values[4]), values[6], values[7], @@ -235,28 +344,9 @@ namespace OpenTK.Platform.Windows new ColorFormat(values[10], values[11], values[12], values[13]), values[15] == 1 ? 2 : 1, values[16] == 1 ? true : false); - - yield return mode; } } - } - - #endregion - - #region ModeSelector - - bool ModeSelector(GraphicsMode current, ColorFormat color, int depth, int stencil, int samples, - ColorFormat accum, int buffers, bool stereo) - { - bool result = - (color != ColorFormat.Empty ? current.ColorFormat >= color : true) && - (depth != 0 ? current.Depth >= depth : true) && - (stencil != 0 ? current.Stencil >= stencil : true) && - (samples != 0 ? current.Samples >= samples : true) && - (accum != ColorFormat.Empty ? current.AccumulatorFormat >= accum : true) && - (buffers != 0 ? current.Buffers >= buffers : true) && - current.Stereo == stereo; - return result; + return created_mode; } #endregion From dfd90c8a43c13d873441e450116b83bc32c2485f Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sat, 21 Dec 2013 23:35:55 +0100 Subject: [PATCH 027/154] Fixed DescribePixelFormatPFD When using the PFD codepath, we now call DescribePixelFormat to retrieve an exact interpretation of the pixel format selected by the driver. --- .../Platform/Windows/WinGraphicsMode.cs | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index e7cf613e..541c13ab 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -191,7 +191,7 @@ namespace OpenTK.Platform.Windows #region ChoosePixelFormatPFD - GraphicsMode ChoosePixelFormatPFD(IntPtr Device, GraphicsMode mode, AccelerationType requested_acceleration_type) + GraphicsMode ChoosePixelFormatPFD(IntPtr device, GraphicsMode mode, AccelerationType requested_acceleration_type) { PixelFormatDescriptor pfd = new PixelFormatDescriptor(); pfd.Size = (short)BlittableValueType.Stride; @@ -209,6 +209,10 @@ namespace OpenTK.Platform.Windows { pfd.DepthBits = (byte)mode.Depth; } + else + { + pfd.Flags |= PixelFormatDescriptorFlags.DEPTH_DONTCARE; + } if (mode.Stencil > 0) { @@ -224,10 +228,14 @@ namespace OpenTK.Platform.Windows pfd.AccumBits = (byte)mode.AccumulatorFormat.BitsPerPixel; } - if (mode.Buffers > 0) + if (mode.Buffers > 1) { pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; } + else if (mode.Buffers == 0) + { + pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER_DONTCARE; + } if (mode.Stereo) { @@ -242,7 +250,7 @@ namespace OpenTK.Platform.Windows } GraphicsMode created_mode = null; - int pixelformat = Functions.ChoosePixelFormat(Device, ref pfd); + int pixelformat = Functions.ChoosePixelFormat(device, ref pfd); if (pixelformat > 0) { AccelerationType acceleration_type = AccelerationType.ICD; @@ -260,7 +268,7 @@ namespace OpenTK.Platform.Windows if (acceleration_type == requested_acceleration_type) { - created_mode = DescribePixelFormatPFD(ref pfd, pixelformat); + created_mode = DescribePixelFormatPFD(device, ref pfd, pixelformat); } } return created_mode; @@ -270,17 +278,22 @@ namespace OpenTK.Platform.Windows #region DescribePixelFormatPFD - static GraphicsMode DescribePixelFormatPFD(ref PixelFormatDescriptor pfd, int pixelformat) + static GraphicsMode DescribePixelFormatPFD(IntPtr device, ref PixelFormatDescriptor pfd, int pixelformat) { - return new GraphicsMode( - new IntPtr(pixelformat), - new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), - pfd.DepthBits, - pfd.StencilBits, - 0, // MSAA not supported - new ColorFormat(pfd.AccumRedBits, pfd.AccumGreenBits, pfd.AccumBlueBits, pfd.AccumAlphaBits), - (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, - (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); + GraphicsMode created_mode = null; + if (Functions.DescribePixelFormat(device, pixelformat, pfd.Size, ref pfd) > 0) + { + created_mode = new GraphicsMode( + new IntPtr(pixelformat), + new ColorFormat(pfd.RedBits, pfd.GreenBits, pfd.BlueBits, pfd.AlphaBits), + pfd.DepthBits, + pfd.StencilBits, + 0, // MSAA not supported when using PixelFormatDescriptor + new ColorFormat(pfd.AccumRedBits, pfd.AccumGreenBits, pfd.AccumBlueBits, pfd.AccumAlphaBits), + (pfd.Flags & PixelFormatDescriptorFlags.DOUBLEBUFFER) != 0 ? 2 : 1, + (pfd.Flags & PixelFormatDescriptorFlags.STEREO) != 0); + } + return created_mode; } #endregion From dec02d5534ebbb2498594f8765f7e2f0e9e75d11 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 09:20:40 +0100 Subject: [PATCH 028/154] Improved WGL mode selection Fixed WGL_ARB_pixel_format attribute selection for doublebuffering, stereoscopic rendering and hardware acceleration. Implemented minimization strategy to select the optimal PixelFormatDescriptor in the fallback path. --- .../Platform/Windows/WinGraphicsMode.cs | 165 ++++++++++-------- 1 file changed, 94 insertions(+), 71 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index 541c13ab..a9544f71 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -105,18 +105,28 @@ namespace OpenTK.Platform.Windows attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); - if (mode.ColorFormat.BitsPerPixel > 0) + if (mode.ColorFormat.Red > 0) { attributes.Add((int)WGL_ARB_pixel_format.RedBitsArb); attributes.Add(mode.ColorFormat.Red); + } + + if (mode.ColorFormat.Green > 0) + { attributes.Add((int)WGL_ARB_pixel_format.GreenBitsArb); attributes.Add(mode.ColorFormat.Green); + } + + if (mode.ColorFormat.Blue > 0) + { attributes.Add((int)WGL_ARB_pixel_format.BlueBitsArb); attributes.Add(mode.ColorFormat.Blue); + } + + if (mode.ColorFormat.Alpha > 0) + { attributes.Add((int)WGL_ARB_pixel_format.AlphaBitsArb); attributes.Add(mode.ColorFormat.Alpha); - attributes.Add((int)WGL_ARB_pixel_format.ColorBitsArb); - attributes.Add(mode.ColorFormat.BitsPerPixel); } if (mode.Depth > 0) @@ -131,18 +141,28 @@ namespace OpenTK.Platform.Windows attributes.Add(mode.Stencil); } - if (mode.AccumulatorFormat.BitsPerPixel > 0) + if (mode.AccumulatorFormat.Red > 0) { attributes.Add((int)WGL_ARB_pixel_format.AccumRedBitsArb); attributes.Add(mode.AccumulatorFormat.Red); + } + + if (mode.AccumulatorFormat.Green > 0) + { attributes.Add((int)WGL_ARB_pixel_format.AccumGreenBitsArb); attributes.Add(mode.AccumulatorFormat.Green); + } + + if (mode.AccumulatorFormat.Blue > 0) + { attributes.Add((int)WGL_ARB_pixel_format.AccumBlueBitsArb); attributes.Add(mode.AccumulatorFormat.Blue); + } + + if (mode.AccumulatorFormat.Alpha > 0) + { attributes.Add((int)WGL_ARB_pixel_format.AccumAlphaBitsArb); attributes.Add(mode.AccumulatorFormat.Alpha); - attributes.Add((int)WGL_ARB_pixel_format.AccumBitsArb); - attributes.Add(mode.AccumulatorFormat.BitsPerPixel); } if (mode.Samples > 0) @@ -156,13 +176,11 @@ namespace OpenTK.Platform.Windows if (mode.Buffers > 0) { attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb); - attributes.Add(mode.Buffers); } if (mode.Stereo) { attributes.Add((int)WGL_ARB_pixel_format.StereoArb); - attributes.Add(1); } attributes.Add(0); @@ -181,7 +199,7 @@ namespace OpenTK.Platform.Windows } else { - Debug.Print("[WGL] ChoosePixelFormatARB not supported"); + Debug.WriteLine("[WGL] ChoosePixelFormatARB not supported on this context"); } return created_mode; @@ -191,94 +209,99 @@ namespace OpenTK.Platform.Windows #region ChoosePixelFormatPFD - GraphicsMode ChoosePixelFormatPFD(IntPtr device, GraphicsMode mode, AccelerationType requested_acceleration_type) + static bool Compare(int got, int requested, ref int distance) { - PixelFormatDescriptor pfd = new PixelFormatDescriptor(); - pfd.Size = (short)BlittableValueType.Stride; - - if (mode.ColorFormat.BitsPerPixel > 0) + if (got < requested) { - pfd.RedBits = (byte)mode.ColorFormat.Red; - pfd.GreenBits = (byte)mode.ColorFormat.Green; - pfd.BlueBits = (byte)mode.ColorFormat.Blue; - pfd.AlphaBits = (byte)mode.ColorFormat.Alpha; - pfd.ColorBits = (byte)mode.ColorFormat.BitsPerPixel; - } - - if (mode.Depth > 0) - { - pfd.DepthBits = (byte)mode.Depth; + return false; } else { - pfd.Flags |= PixelFormatDescriptorFlags.DEPTH_DONTCARE; + distance += got - requested; + return true; } + } - if (mode.Stencil > 0) + static AccelerationType GetAccelerationType(ref PixelFormatDescriptor pfd) + { + AccelerationType type = AccelerationType.ICD; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) { - pfd.StencilBits = (byte)mode.Stencil; + if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0) + { + type = AccelerationType.MCD; + } + else + { + type = AccelerationType.None; + } } + return type; + } - if (mode.AccumulatorFormat.BitsPerPixel > 0) - { - pfd.AccumRedBits = (byte)mode.AccumulatorFormat.Red; - pfd.AccumGreenBits = (byte)mode.AccumulatorFormat.Green; - pfd.AccumBlueBits = (byte)mode.AccumulatorFormat.Blue; - pfd.AccumAlphaBits = (byte)mode.AccumulatorFormat.Alpha; - pfd.AccumBits = (byte)mode.AccumulatorFormat.BitsPerPixel; - } - - if (mode.Buffers > 1) - { - pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; - } - else if (mode.Buffers == 0) - { - pfd.Flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER_DONTCARE; - } + GraphicsMode ChoosePixelFormatPFD(IntPtr device, GraphicsMode mode, AccelerationType requested_acceleration_type) + { + PixelFormatDescriptor pfd = new PixelFormatDescriptor(); + PixelFormatDescriptorFlags flags = 0; + flags |= PixelFormatDescriptorFlags.DRAW_TO_WINDOW; + flags |= PixelFormatDescriptorFlags.SUPPORT_OPENGL; if (mode.Stereo) { - pfd.Flags |= PixelFormatDescriptorFlags.DRAW_TO_WINDOW; - pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_OPENGL; + flags |= PixelFormatDescriptorFlags.STEREO; + } + if (mode.Buffers > 1) + { + // On Win7 64bit + Nvidia 650M, no pixel format advertises DOUBLEBUFFER. + // Adding this check here causes mode selection to fail. + // Does not appear to be supported by DescribePixelFormat + //flags |= PixelFormatDescriptorFlags.DOUBLEBUFFER; + } + if (System.Environment.OSVersion.Version.Major >= 6) + { + flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION; } - // Make sure we don't turn off Aero on Vista and newer. - if (Environment.OSVersion.Version.Major >= 6) - { - pfd.Flags |= PixelFormatDescriptorFlags.SUPPORT_COMPOSITION; - } + int count = Functions.DescribePixelFormat(device, 1, API.PixelFormatDescriptorSize, ref pfd); - GraphicsMode created_mode = null; - int pixelformat = Functions.ChoosePixelFormat(device, ref pfd); - if (pixelformat > 0) + int best = 0; + int best_dist = int.MaxValue; + for (int index = 1; index <= count; index++) { - AccelerationType acceleration_type = AccelerationType.ICD; - if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_FORMAT) != 0) - { - if ((pfd.Flags & PixelFormatDescriptorFlags.GENERIC_ACCELERATED) != 0) - { - acceleration_type = AccelerationType.MCD; - } - else - { - acceleration_type = AccelerationType.None; - } - } + int dist = 0; + bool valid = Functions.DescribePixelFormat(device, index, API.PixelFormatDescriptorSize, ref pfd) != 0; + valid &= GetAccelerationType(ref pfd) == requested_acceleration_type; + valid &= (pfd.Flags & flags) == flags; + valid &= pfd.PixelType == PixelType.RGBA; // indexed modes not currently supported + valid &= Compare(pfd.ColorBits, mode.ColorFormat.BitsPerPixel, ref dist); + valid &= Compare(pfd.RedBits, mode.ColorFormat.Red, ref dist); + valid &= Compare(pfd.GreenBits, mode.ColorFormat.Green, ref dist); + valid &= Compare(pfd.BlueBits, mode.ColorFormat.Blue, ref dist); + valid &= Compare(pfd.AlphaBits, mode.ColorFormat.Alpha, ref dist); + valid &= Compare(pfd.AccumBits, mode.AccumulatorFormat.BitsPerPixel, ref dist); + valid &= Compare(pfd.AccumRedBits, mode.AccumulatorFormat.Red, ref dist); + valid &= Compare(pfd.AccumGreenBits, mode.AccumulatorFormat.Green, ref dist); + valid &= Compare(pfd.AccumBlueBits, mode.AccumulatorFormat.Blue, ref dist); + valid &= Compare(pfd.AccumAlphaBits, mode.AccumulatorFormat.Alpha, ref dist); + valid &= Compare(pfd.DepthBits, mode.Depth, ref dist); + valid &= Compare(pfd.StencilBits, mode.Stencil, ref dist); - if (acceleration_type == requested_acceleration_type) + if (valid && dist < best_dist) { - created_mode = DescribePixelFormatPFD(device, ref pfd, pixelformat); + best = index; + best_dist = dist; } } - return created_mode; + + return DescribePixelFormatPFD(device, ref pfd, best); } #endregion #region DescribePixelFormatPFD - static GraphicsMode DescribePixelFormatPFD(IntPtr device, ref PixelFormatDescriptor pfd, int pixelformat) + static GraphicsMode DescribePixelFormatPFD(IntPtr device, ref PixelFormatDescriptor pfd, + int pixelformat) { GraphicsMode created_mode = null; if (Functions.DescribePixelFormat(device, pixelformat, pfd.Size, ref pfd) > 0) @@ -345,7 +368,7 @@ namespace OpenTK.Platform.Windows } // Skip formats that don't offer full hardware acceleration - WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)attribs[0]; + WGL_ARB_pixel_format acceleration = (WGL_ARB_pixel_format)values[0]; if (acceleration == WGL_ARB_pixel_format.FullAccelerationArb) { // Construct a new GraphicsMode to describe this format From dbabb6c8383fb9a666d42bacc2c13d0791e456b5 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 10:35:05 +0100 Subject: [PATCH 029/154] Added WGL_DRAW_TO_WINDOW_ARB flag Without this flag, OpenGL rendering does not work as expected. Additionally, all WGL_ARB_pixel_format attributes are expected to be specified in key-value pairs. Fixed double-buffering and stereoscoping rendering attributes. --- Source/OpenTK/Platform/Windows/WinGraphicsMode.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs index a9544f71..9de28341 100644 --- a/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs +++ b/Source/OpenTK/Platform/Windows/WinGraphicsMode.cs @@ -104,6 +104,9 @@ namespace OpenTK.Platform.Windows List attributes = new List(); attributes.Add((int)WGL_ARB_pixel_format.AccelerationArb); attributes.Add((int)WGL_ARB_pixel_format.FullAccelerationArb); + + attributes.Add((int)WGL_ARB_pixel_format.DrawToWindowArb); + attributes.Add(1); if (mode.ColorFormat.Red > 0) { @@ -176,11 +179,13 @@ namespace OpenTK.Platform.Windows if (mode.Buffers > 0) { attributes.Add((int)WGL_ARB_pixel_format.DoubleBufferArb); + attributes.Add(mode.Buffers > 1 ? 1 : 0); } if (mode.Stereo) { attributes.Add((int)WGL_ARB_pixel_format.StereoArb); + attributes.Add(1); } attributes.Add(0); From 12cceacf608ceddc3d7c0359a28da7409aec0e06 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 11:10:05 +0100 Subject: [PATCH 030/154] Fixed crash in MakeCurrent(null) MakeCurrent(null) should set the bound device context to zero. --- Source/OpenTK/Platform/Windows/WinGLContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinGLContext.cs b/Source/OpenTK/Platform/Windows/WinGLContext.cs index 0e727df7..837c3e76 100644 --- a/Source/OpenTK/Platform/Windows/WinGLContext.cs +++ b/Source/OpenTK/Platform/Windows/WinGLContext.cs @@ -279,14 +279,14 @@ namespace OpenTK.Platform.Windows throw new ArgumentException("window", "Must point to a valid window."); success = Wgl.MakeCurrent(wnd.DeviceContext, Handle.Handle); + device_context = wnd.DeviceContext; } else { success = Wgl.MakeCurrent(IntPtr.Zero, IntPtr.Zero); + device_context = IntPtr.Zero; } - device_context = wnd.DeviceContext; - if (!success) { throw new GraphicsContextException(String.Format( From 7692243cd2250c9ed374a918144b3c4d04f5ebb4 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 15:40:01 +0100 Subject: [PATCH 031/154] Remove bogus GraphicsMode.Index check. Fixes #22 GraphicsMode.Index is set by the platform-specific context constructor, which is invoked after the X11GLControl constructor. It does not make sense to check GraphicsMode.Index in the X11GLControl constructor, as it is never set at that point. --- Source/GLControl/X11GLControl.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/GLControl/X11GLControl.cs b/Source/GLControl/X11GLControl.cs index 98c0de82..19d036b7 100644 --- a/Source/GLControl/X11GLControl.cs +++ b/Source/GLControl/X11GLControl.cs @@ -76,8 +76,6 @@ namespace OpenTK throw new ArgumentNullException("mode"); if (control == null) throw new ArgumentNullException("control"); - if (!mode.Index.HasValue) - throw new GraphicsModeException("Invalid or unsupported GraphicsMode."); this.mode = mode; From cbc39f922df6d3dbc2b670299943749c7c7993d6 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 22:01:04 +0100 Subject: [PATCH 032/154] Implemented IEquatable<> interface --- Source/OpenTK/Input/GamePadButtons.cs | 30 ++++++++++++- Source/OpenTK/Input/GamePadCapabilities.cs | 46 ++++++++++++++++++- Source/OpenTK/Input/GamePadDPad.cs | 51 +++++++++++++++++++++- Source/OpenTK/Input/GamePadState.cs | 32 +++++++++++++- 4 files changed, 155 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index 199e593f..5d423ddb 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -107,9 +107,37 @@ namespace OpenTK.Input return !left.Equals(right); } + public override string ToString() + { + return String.Format( + "{{ABXYLR: {0}{1}{2}{3}{4}{5}; Back: {6}; BigButton: {7}; LStick: {8}; RStick: {9}}}", + A == ButtonState.Pressed ? "1" : "0", + B == ButtonState.Pressed ? "1" : "0", + X == ButtonState.Pressed ? "1" : "0", + Y == ButtonState.Pressed ? "1" : "0", + LeftShoulder == ButtonState.Pressed ? "1" : "0", + RightShoulder == ButtonState.Pressed ? "1" : "0", + Back == ButtonState.Pressed ? "1" : "0", + BigButton == ButtonState.Pressed ? "1" : "0", + LeftStick == ButtonState.Pressed ? "1" : "0", + RightStick == ButtonState.Pressed ? "1" : "0"); + } + + public override int GetHashCode() + { + return buttons.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadButtons && + Equals((GamePadButtons)obj); + } + #endregion - #region IEquatable Members + #region IEquatable Members public bool Equals(GamePadButtons other) { diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 23c56cd3..767e0198 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -32,7 +32,7 @@ using System; namespace OpenTK.Input { - public struct GamePadCapabilities + public struct GamePadCapabilities : IEquatable { byte axis_count; byte button_count; @@ -62,6 +62,50 @@ namespace OpenTK.Input get { return trackball_count; } internal set { trackball_count = (byte)value; } } + + public static bool operator ==(GamePadCapabilities left, GamePadCapabilities right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadCapabilities left, GamePadCapabilities right) + { + return !left.Equals(right); + } + + public override string ToString() + { + return String.Format( + "{{Axes: {0}; Buttons: {1}; DPads: {2}; Trackballs: {3}}}", + AxisCount, ButtonCount, DPadCount, TrackballCount); + } + + public override int GetHashCode() + { + return + AxisCount.GetHashCode() ^ ButtonCount.GetHashCode() ^ + DPadCount.GetHashCode() ^ TrackballCount.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadCapabilities && + Equals((GamePadCapabilities)obj); + } + + #region IEquatable Members + + public bool Equals(GamePadCapabilities other) + { + return + AxisCount == other.AxisCount && + ButtonCount == other.ButtonCount && + DPadCount == other.DPadCount && + TrackballCount == other.TrackballCount; + } + + #endregion } } diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs index 72389b00..06ba2262 100644 --- a/Source/OpenTK/Input/GamePadDPad.cs +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -31,7 +31,7 @@ using System; namespace OpenTK.Input { - public struct GamePadDPad + public struct GamePadDPad : IEquatable { [Flags] enum DPadButtons : byte @@ -44,6 +44,8 @@ namespace OpenTK.Input DPadButtons buttons; + #region Public Members + internal GamePadDPad(Buttons state) { // DPad butons are stored in the lower 4bits @@ -75,6 +77,42 @@ namespace OpenTK.Input internal set { SetButton(DPadButtons.Right, value); } } + public static bool operator ==(GamePadDPad left, GamePadDPad right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadDPad left, GamePadDPad right) + { + return !left.Equals(right); + } + + public override string ToString() + { + return String.Format( + "{{ULDR: {0}{1}{2}{3}}}", + IsUp ? "1" : "0", + IsLeft ? "1" : "0", + IsDown ? "1" : "0", + IsRight ? "1" : "0"); + } + + public override int GetHashCode() + { + return buttons.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadDPad && + Equals((GamePadDPad)obj); + } + + #endregion + + #region Private Members + void SetButton(DPadButtons button, bool value) { if (value) @@ -86,5 +124,16 @@ namespace OpenTK.Input buttons &= ~button; } } + + #endregion + + #region IEquatable Members + + public bool Equals(GamePadDPad other) + { + return buttons == other.buttons; + } + + #endregion } } diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index d45787bb..e85187f8 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -32,7 +32,7 @@ namespace OpenTK.Input /// /// Encapsulates the state of a GamePad device. /// - public struct GamePadState /*: IEquatable*/ + public struct GamePadState : IEquatable { const float RangeMultiplier = 1.0f / (short.MaxValue + 1); @@ -62,6 +62,36 @@ namespace OpenTK.Input get { return is_connected; } } + public override string ToString() + { + return String.Format( + "{{Buttons: {0}; DPad: {1}; IsConnected: {2}", + Buttons, DPad, IsConnected); + } + + public override int GetHashCode() + { + return Buttons.GetHashCode() ^ DPad.GetHashCode() ^ IsConnected.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadState && + Equals((GamePadState)obj); + } + + #endregion + + #region IEquatable Members + public bool Equals(GamePadState other) + { + return + Buttons == other.Buttons && + DPad == other.DPad && + IsConnected == other.IsConnected; + } + #endregion #region Internal Members From ef580daf7545ed75e2feaf4b9fa3c0df473e894e Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 22:07:30 +0100 Subject: [PATCH 033/154] More compact string representation --- Source/OpenTK/Input/GamePadButtons.cs | 22 +++++++++++----------- Source/OpenTK/Input/GamePadDPad.cs | 10 +++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index 5d423ddb..0bc2988f 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -110,17 +110,17 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{ABXYLR: {0}{1}{2}{3}{4}{5}; Back: {6}; BigButton: {7}; LStick: {8}; RStick: {9}}}", - A == ButtonState.Pressed ? "1" : "0", - B == ButtonState.Pressed ? "1" : "0", - X == ButtonState.Pressed ? "1" : "0", - Y == ButtonState.Pressed ? "1" : "0", - LeftShoulder == ButtonState.Pressed ? "1" : "0", - RightShoulder == ButtonState.Pressed ? "1" : "0", - Back == ButtonState.Pressed ? "1" : "0", - BigButton == ButtonState.Pressed ? "1" : "0", - LeftStick == ButtonState.Pressed ? "1" : "0", - RightStick == ButtonState.Pressed ? "1" : "0"); + "{{{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}}}", + A == ButtonState.Pressed ? "A" : String.Empty, + B == ButtonState.Pressed ? "B" : String.Empty, + X == ButtonState.Pressed ? "X" : String.Empty, + Y == ButtonState.Pressed ? "Y" : String.Empty, + LeftShoulder == ButtonState.Pressed ? "L" : String.Empty, + RightShoulder == ButtonState.Pressed ? "R" : String.Empty, + Back == ButtonState.Pressed ? " Back" : String.Empty, + BigButton == ButtonState.Pressed ? " Big" : String.Empty, + LeftStick == ButtonState.Pressed ? " LStick" : String.Empty, + RightStick == ButtonState.Pressed ? " RStick" : String.Empty); } public override int GetHashCode() diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs index 06ba2262..375036a2 100644 --- a/Source/OpenTK/Input/GamePadDPad.cs +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -90,11 +90,11 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{ULDR: {0}{1}{2}{3}}}", - IsUp ? "1" : "0", - IsLeft ? "1" : "0", - IsDown ? "1" : "0", - IsRight ? "1" : "0"); + "{{{0}{1}{2}{3}}}", + IsUp ? "U" : String.Empty, + IsLeft ? "L" : String.Empty, + IsDown ? "D" : String.Empty, + IsRight ? "R" : String.Empty); } public override int GetHashCode() From 487e67473faa4820ed5e7e0e3bc4628b9927fed9 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 22:07:40 +0100 Subject: [PATCH 034/154] Added state information for GamePads --- Source/Examples/OpenTK/Test/GameWindowStates.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index cdb5afa2..99724300 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -239,6 +239,8 @@ namespace Examples.Tests DrawKeyboard(gfx, keyboard, line++); DrawMouse(gfx, mouse, line++); DrawJoysticks(gfx, Joysticks, line++); + + line = DrawGamePads(gfx, line); } } @@ -249,7 +251,19 @@ namespace Examples.Tests PixelType.UnsignedByte, data.Scan0); TextBitmap.UnlockBits(data); } - + + int DrawGamePads(Graphics gfx, int line) + { + DrawString(gfx, "GamePads:", line++); + for (int i = 0; i < 4; i++) + { + GamePadCapabilities caps = GamePad.GetCapabilities(i); + GamePadState state = GamePad.GetState(i); + DrawString(gfx, caps.ToString(), line++); + DrawString(gfx, state.ToString(), line++); + } + return line; + } protected override void OnLoad(EventArgs e) { From 1e62821bf19598f97437b2052c34553364ccc295 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 22:32:18 +0100 Subject: [PATCH 035/154] Implemented GamePadThumbSticks --- Source/OpenTK/Input/GamePadAxis.cs | 28 ++---- Source/OpenTK/Input/GamePadState.cs | 50 ++++++---- Source/OpenTK/Input/GamePadThumbSticks.cs | 111 ++++++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 1 + 4 files changed, 149 insertions(+), 41 deletions(-) create mode 100644 Source/OpenTK/Input/GamePadThumbSticks.cs diff --git a/Source/OpenTK/Input/GamePadAxis.cs b/Source/OpenTK/Input/GamePadAxis.cs index dd6b3192..f619ab6a 100644 --- a/Source/OpenTK/Input/GamePadAxis.cs +++ b/Source/OpenTK/Input/GamePadAxis.cs @@ -27,28 +27,12 @@ using System; namespace OpenTK.Input { - public enum GamePadAxis + internal enum GamePadAxis { - /// The first axis of the gamepad. - Axis0 = 0, - /// The second axis of the gamepad. - Axis1, - /// The third axis of the gamepad. - Axis2, - /// The fourth axis of the gamepad. - Axis3, - /// The fifth axis of the gamepad. - Axis4, - /// The sixth axis of the gamepad. - Axis5, - /// The seventh axis of the gamepad. - Axis6, - /// The eighth axis of the gamepad. - Axis7, - /// The ninth axis of the gamepad. - Axis8, - /// The tenth axis of the gamepad. - Axis9, - } + LeftX, + LeftY, + RightX, + RightY + } } diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index e85187f8..ad603017 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -37,14 +37,17 @@ namespace OpenTK.Input const float RangeMultiplier = 1.0f / (short.MaxValue + 1); Buttons buttons; - unsafe fixed short axes[GamePad.MaxAxisCount]; + short left_stick_x; + short left_stick_y; + short right_stick_x; + short right_stick_y; bool is_connected; #region Public Members - public float GetAxis(GamePadAxis axis) + public GamePadThumbSticks ThumbSticks { - throw new NotImplementedException(); + get { return new GamePadThumbSticks(left_stick_x, left_stick_y, right_stick_x, right_stick_y); } } public GamePadButtons Buttons @@ -65,13 +68,15 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Buttons: {0}; DPad: {1}; IsConnected: {2}", - Buttons, DPad, IsConnected); + "{{Sticks: {0}; Buttons: {1}; DPad: {2}; IsConnected: {3}", + ThumbSticks, Buttons, DPad, IsConnected); } public override int GetHashCode() { - return Buttons.GetHashCode() ^ DPad.GetHashCode() ^ IsConnected.GetHashCode(); + return + ThumbSticks.GetHashCode() ^ Buttons.GetHashCode() ^ + DPad.GetHashCode() ^ IsConnected.GetHashCode(); } public override bool Equals(object obj) @@ -87,6 +92,7 @@ namespace OpenTK.Input public bool Equals(GamePadState other) { return + ThumbSticks == other.ThumbSticks && Buttons == other.Buttons && DPad == other.DPad && IsConnected == other.IsConnected; @@ -98,20 +104,26 @@ namespace OpenTK.Input internal void SetAxis(GamePadAxis axis, short value) { - if (IsAxisValid(axis)) + switch (axis) { - int index = (int)axis; - unsafe - { - fixed (short *paxes = axes) - { - *(paxes + index) = value; - } - } - } - else - { - throw new ArgumentOutOfRangeException("axis"); + case GamePadAxis.LeftX: + left_stick_x = value; + break; + + case GamePadAxis.LeftY: + left_stick_y = value; + break; + + case GamePadAxis.RightX: + right_stick_x = value; + break; + + case GamePadAxis.RightY: + right_stick_x = value; + break; + + default: + throw new ArgumentOutOfRangeException("axis"); } } diff --git a/Source/OpenTK/Input/GamePadThumbSticks.cs b/Source/OpenTK/Input/GamePadThumbSticks.cs new file mode 100644 index 00000000..e7c9d187 --- /dev/null +++ b/Source/OpenTK/Input/GamePadThumbSticks.cs @@ -0,0 +1,111 @@ +using System; +// #region License +// +// GamePadThumbSticks.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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.Collections.Generic; +using System.Text; + +namespace OpenTK.Input +{ + public struct GamePadThumbSticks : IEquatable + { + const float ConversionFactor = 1.0f / short.MaxValue; + short left_x, left_y; + short right_x, right_y; + + internal GamePadThumbSticks( + short left_x, short left_y, + short right_x, short right_y) + { + this.left_x = left_x; + this.left_y = left_y; + this.right_x = right_x; + this.right_y = right_y; + } + + #region Public Members + + public Vector2 Left + { + get { return new Vector2(left_x * ConversionFactor, left_y * ConversionFactor); } + } + + public Vector2 Right + { + get { return new Vector2(right_x * ConversionFactor, right_y * ConversionFactor); } + } + + public static bool operator ==(GamePadThumbSticks left, GamePadThumbSticks right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadThumbSticks left, GamePadThumbSticks right) + { + return !left.Equals(right); + } + + public override string ToString() + { + return String.Format( + "{{Left: {0}; Right: {1}}}", + Left, Right); + } + + public override int GetHashCode() + { + return + left_x.GetHashCode() ^ left_y.GetHashCode() ^ + right_x.GetHashCode() ^ right_y.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadThumbSticks && + Equals((GamePadThumbSticks)obj); + } + + #endregion + + #region IEquatable Members + + public bool Equals(GamePadThumbSticks other) + { + return + left_x == other.left_x && + left_y == other.left_y && + right_x == other.right_x && + right_y == other.right_y; + } + + #endregion + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 723b4412..aa83bbee 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -133,6 +133,7 @@ + From 7016ad33124cff28ce310d14cb92ba4927b22e45 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 22:32:24 +0100 Subject: [PATCH 036/154] Added missing newline --- Source/OpenTK/Input/GamePadDPad.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs index 375036a2..8e1a0588 100644 --- a/Source/OpenTK/Input/GamePadDPad.cs +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -26,6 +26,7 @@ // THE SOFTWARE. // // #endregion + using System; namespace OpenTK.Input From 16d5055cb12b9840a48274d0f1e30820c73bc6ce Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 22:34:34 +0100 Subject: [PATCH 037/154] Cleaned up using directives --- Source/OpenTK/Input/GamePadThumbSticks.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Input/GamePadThumbSticks.cs b/Source/OpenTK/Input/GamePadThumbSticks.cs index e7c9d187..59eb4ee3 100644 --- a/Source/OpenTK/Input/GamePadThumbSticks.cs +++ b/Source/OpenTK/Input/GamePadThumbSticks.cs @@ -1,5 +1,4 @@ -using System; -// #region License +// #region License // // GamePadThumbSticks.cs // @@ -29,8 +28,7 @@ // #endregion -using System.Collections.Generic; -using System.Text; +using System; namespace OpenTK.Input { From 98b4883efd98b571cb4a949dfbbd6cf6fbafd4ed Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 22:47:50 +0100 Subject: [PATCH 038/154] Fixed x/y axis mixup. --- Source/OpenTK/Input/GamePadState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index ad603017..b0501f6c 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -119,7 +119,7 @@ namespace OpenTK.Input break; case GamePadAxis.RightY: - right_stick_x = value; + right_stick_y = value; break; default: From 6d0427b928c37fc444d99c7ec8ebd5a126fec5dc Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 23:12:53 +0100 Subject: [PATCH 039/154] Added SDL_InitSubSystem method --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 2232e686..163d393b 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -233,6 +233,10 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_Init", ExactSpelling = true)] public static extern int Init(SystemFlags flags); + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_InitSubSystem", ExactSpelling = true)] + public static extern int InitSubSystem(SystemFlags flags); + /// /// Determines if the specified joystick is supported by the GameController API. /// From 5958db383d63d0112cf9eac41c0666da068741a7 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 23:13:21 +0100 Subject: [PATCH 040/154] Delay joystick initialization until necessary --- Source/OpenTK/Configuration.cs | 4 ++-- Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Configuration.cs b/Source/OpenTK/Configuration.cs index 98aad59d..fcae8212 100644 --- a/Source/OpenTK/Configuration.cs +++ b/Source/OpenTK/Configuration.cs @@ -206,8 +206,8 @@ namespace OpenTK { if (!OpenTK.Platform.SDL2.SDL.WasInit(0)) { - var flags = OpenTK.Platform.SDL2.SystemFlags.EVERYTHING; - flags &= ~OpenTK.Platform.SDL2.SystemFlags.AUDIO; + var flags = + OpenTK.Platform.SDL2.SystemFlags.VIDEO | Platform.SDL2.SystemFlags.TIMER; if (OpenTK.Platform.SDL2.SDL.Init(flags) == 0) { supported = true; diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index de174875..d2fa0093 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -59,6 +59,7 @@ namespace OpenTK.Platform.SDL2 driver_handle = new IntPtr(count++); DriverHandles.Add(driver_handle, this); SDL.AddEventWatch(EventFilterDelegate, driver_handle); + SDL.InitSubSystem(SystemFlags.JOYSTICK | SystemFlags.GAMECONTROLLER); } } From c1783c9f264543843d5f84fbac6854640beafc9c Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 23:54:55 +0100 Subject: [PATCH 041/154] Reuse Sdl2Factory.InputDriver in Sdl2NativeWindow --- Source/OpenTK/Platform/SDL2/Sdl2Factory.cs | 4 ++-- Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs index 9f2447ba..4c39156f 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs @@ -34,7 +34,7 @@ namespace OpenTK.Platform.SDL2 { class Sdl2Factory : IPlatformFactory { - readonly IInputDriver2 InputDriver = new Sdl2InputDriver(); + readonly Sdl2InputDriver InputDriver = new Sdl2InputDriver(); bool disposed; /// @@ -58,7 +58,7 @@ namespace OpenTK.Platform.SDL2 public 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); + return new Sdl2NativeWindow(x, y, width, height, title, options, device, InputDriver); } public IDisplayDeviceDriver CreateDisplayDeviceDriver() diff --git a/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs b/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs index dd26d534..9f24fdf7 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs @@ -70,7 +70,7 @@ namespace OpenTK.Platform.SDL2 // Argument for KeyDown and KeyUp events (allocated once to avoid runtime allocations) readonly KeyboardKeyEventArgs key_args = new KeyboardKeyEventArgs(); - readonly IInputDriver input_driver = new Sdl2InputDriver(); + readonly IInputDriver input_driver; readonly EventFilter EventFilterDelegate_GCUnsafe = FilterEvents; readonly IntPtr EventFilterDelegate; @@ -81,10 +81,13 @@ namespace OpenTK.Platform.SDL2 static readonly Sdl2KeyMap map = new Sdl2KeyMap(); public Sdl2NativeWindow(int x, int y, int width, int height, - string title, GameWindowFlags options, DisplayDevice device) + string title, GameWindowFlags options, DisplayDevice device, + IInputDriver input_driver) { lock (sync) { + this.input_driver = input_driver; + var bounds = device.Bounds; var flags = TranslateFlags(options); flags |= WindowFlags.OPENGL; From 9936fa4cc52246a8614846e412c55c9656a4624a Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 23:55:28 +0100 Subject: [PATCH 042/154] Log errors in subsystem initialization --- Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index d2fa0093..3a69be40 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -59,7 +59,14 @@ namespace OpenTK.Platform.SDL2 driver_handle = new IntPtr(count++); DriverHandles.Add(driver_handle, this); SDL.AddEventWatch(EventFilterDelegate, driver_handle); - SDL.InitSubSystem(SystemFlags.JOYSTICK | SystemFlags.GAMECONTROLLER); + if (SDL.InitSubSystem(SystemFlags.JOYSTICK) < 0) + { + Debug.Print("[SDL2] InputDriver failed to init Joystick subsystem. Error: {0}", SDL.GetError()); + } + if (SDL.InitSubSystem(SystemFlags.GAMECONTROLLER) < 0) + { + Debug.Print("[SDL2] InputDriver failed to init GameController subsystem. Error: {0}", SDL.GetError()); + } } } From 033ba43b7091b8008c1196813d7333e5dcfda4e1 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Sun, 22 Dec 2013 23:55:46 +0100 Subject: [PATCH 043/154] Fixed expansion of joysticks collection --- Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 2af3f977..ea0f2433 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -55,7 +55,7 @@ namespace OpenTK.Platform.SDL2 } } - readonly List joysticks = new List(); + readonly List joysticks = new List(4); readonly Dictionary controllers = new Dictionary(); IList joysticks_readonly; @@ -131,16 +131,18 @@ namespace OpenTK.Platform.SDL2 case EventType.JOYDEVICEADDED: { // Make sure we have enough space to store this instance - if (joysticks.Count <= id) + if (joysticks.Capacity <= id) { - joysticks.Capacity = OpenTK.MathHelper.NextPowerOfTwo(id); + joysticks.Capacity = OpenTK.MathHelper.NextPowerOfTwo(id + 1); + for (int i = joysticks.Count; i < joysticks.Capacity; i++) + joysticks.Add(null); // Expand the joysticks list } IntPtr handle = SDL.JoystickOpen(id); if (handle != IntPtr.Zero) { JoystickDevice joystick = OpenJoystick(id); - if (joysticks != null) + if (joystick != null) { joystick.Details.IsConnected = true; joysticks[id] = joystick; From 8350e8e2cec262def63e745e506c7bf3b078c053 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Mon, 23 Dec 2013 00:17:13 +0100 Subject: [PATCH 044/154] More robust handling of device add/remove events --- .../Platform/SDL2/Sdl2JoystickDriver.cs | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index ea0f2433..6c7e2728 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -56,6 +56,7 @@ namespace OpenTK.Platform.SDL2 } readonly List joysticks = new List(4); + readonly Dictionary sdl_joyid_to_joysticks = new Dictionary(); readonly Dictionary controllers = new Dictionary(); IList joysticks_readonly; @@ -130,14 +131,6 @@ namespace OpenTK.Platform.SDL2 { case EventType.JOYDEVICEADDED: { - // Make sure we have enough space to store this instance - if (joysticks.Capacity <= id) - { - joysticks.Capacity = OpenTK.MathHelper.NextPowerOfTwo(id + 1); - for (int i = joysticks.Count; i < joysticks.Capacity; i++) - joysticks.Add(null); // Expand the joysticks list - } - IntPtr handle = SDL.JoystickOpen(id); if (handle != IntPtr.Zero) { @@ -145,7 +138,13 @@ namespace OpenTK.Platform.SDL2 if (joystick != null) { joystick.Details.IsConnected = true; - joysticks[id] = joystick; + if (!sdl_joyid_to_joysticks.ContainsKey(id)) + { + sdl_joyid_to_joysticks.Add(id, joysticks.Count); + joysticks.Add(null); + } + int index = sdl_joyid_to_joysticks[id]; + joysticks[index] = joystick; } } } @@ -153,7 +152,8 @@ namespace OpenTK.Platform.SDL2 case EventType.JOYDEVICEREMOVED: { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; joystick.Details.IsConnected = false; } break; @@ -165,7 +165,8 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsJoystickValid(id)) { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; float value = ev.Value * RangeMultiplier; joystick.SetAxis((JoystickAxis)ev.Axis, value); } @@ -180,7 +181,8 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsJoystickValid(id)) { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; // Todo: does it make sense to support balls? } else @@ -194,7 +196,8 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsJoystickValid(id)) { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; joystick.SetButton((JoystickButton)ev.Button, ev.State == State.Pressed); } else @@ -208,7 +211,8 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsJoystickValid(id)) { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; // Todo: map hat to an extra axis } else @@ -224,15 +228,15 @@ namespace OpenTK.Platform.SDL2 switch (ev.Type) { case EventType.CONTROLLERDEVICEADDED: - if (SDL.IsGameController(id)) + IntPtr handle = SDL.GameControllerOpen(id); + if (handle != IntPtr.Zero) { - IntPtr handle = SDL.GameControllerOpen(id); - if (handle != IntPtr.Zero) - { - Sdl2GamePad pad = new Sdl2GamePad(handle); - pad.State.SetConnected(true); - controllers.Add(id, pad); - } + Sdl2GamePad pad = new Sdl2GamePad(handle); + pad.State.SetConnected(true); + // Check whether the device has ever been connected before + if (!controllers.ContainsKey(id)) + controllers.Add(id, null); + controllers[id] = pad; } break; From 61f0918544a676676203facebb6e3a34bfa2d5de Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Mon, 23 Dec 2013 01:29:12 +0100 Subject: [PATCH 045/154] Fixed rendering of joysticks and gamepads Joysticks and gamepad states would overlap, causing some lines to be unreadable. This is now fixed. --- Source/Examples/OpenTK/Test/GameWindowStates.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 99724300..cc3b29b1 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -163,7 +163,7 @@ namespace Examples.Tests } } - static void DrawJoysticks(Graphics gfx, IList joysticks, int line) + static int DrawJoysticks(Graphics gfx, IList joysticks, int line) { float space = gfx.MeasureString(" ", TextFont).Width; @@ -192,6 +192,8 @@ namespace Examples.Tests line++; } + + return line; } protected override void OnUpdateFrame(FrameEventArgs e) @@ -238,9 +240,8 @@ namespace Examples.Tests DrawString(gfx, TypedText.ToString(), line++); DrawKeyboard(gfx, keyboard, line++); DrawMouse(gfx, mouse, line++); - DrawJoysticks(gfx, Joysticks, line++); - - line = DrawGamePads(gfx, line); + line = DrawJoysticks(gfx, Joysticks, line++); + line = DrawGamePads(gfx, line++); } } From c89ddaa2254a0f380501ccc1b69f8a16e974a4fe Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Mon, 23 Dec 2013 01:49:49 +0100 Subject: [PATCH 046/154] Display start button in ToString() --- Source/OpenTK/Input/GamePadButtons.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index 0bc2988f..aeb97b59 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -118,6 +118,7 @@ namespace OpenTK.Input LeftShoulder == ButtonState.Pressed ? "L" : String.Empty, RightShoulder == ButtonState.Pressed ? "R" : String.Empty, Back == ButtonState.Pressed ? " Back" : String.Empty, + Start == ButtonState.Pressed ? " Start" : String.Empty, BigButton == ButtonState.Pressed ? " Big" : String.Empty, LeftStick == ButtonState.Pressed ? " LStick" : String.Empty, RightStick == ButtonState.Pressed ? " RStick" : String.Empty); From f9394b9ba6cced5185999139aaf76d719c0fd0ca Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Mon, 23 Dec 2013 01:50:13 +0100 Subject: [PATCH 047/154] Removed unnecessary IsButtonValid method --- Source/OpenTK/Input/GamePad.cs | 1 - Source/OpenTK/Input/GamePadState.cs | 22 +++------------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/Source/OpenTK/Input/GamePad.cs b/Source/OpenTK/Input/GamePad.cs index 7a2fc066..a0a63f49 100644 --- a/Source/OpenTK/Input/GamePad.cs +++ b/Source/OpenTK/Input/GamePad.cs @@ -35,7 +35,6 @@ namespace OpenTK.Input public class GamePad { internal const int MaxAxisCount = 10; - internal const int MaxButtonCount = 16; // if this grows over 32 then GamePadState.buttons must be modified internal const int MaxDPadCount = 2; static readonly IGamePadDriver driver = diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index b0501f6c..ceec371f 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -129,23 +129,13 @@ namespace OpenTK.Input internal void SetButton(Buttons button, bool pressed) { - if (IsButtonValid(button)) + if (pressed) { - int index = (int)button; - - Buttons mask = (Buttons)(1 << index); - if (pressed) - { - buttons |= mask; - } - else - { - buttons &= ~mask; - } + buttons |= button; } else { - throw new ArgumentOutOfRangeException("button"); + buttons &= ~button; } } @@ -164,12 +154,6 @@ namespace OpenTK.Input return index >= 0 && index < GamePad.MaxAxisCount; } - bool IsButtonValid(Buttons button) - { - int index = (int)button; - return index >= 0 && index < GamePad.MaxButtonCount; - } - bool IsDPadValid(int index) { return index >= 0 && index < GamePad.MaxDPadCount; From a7db0d76db7e5b409b55f5f132725b0e551885d3 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Mon, 23 Dec 2013 01:50:25 +0100 Subject: [PATCH 048/154] Implemented GamePad API (WIP) --- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index ca229700..07c208cc 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -133,6 +133,11 @@ namespace OpenTK.Platform.Windows return stick; } + bool IsValid(int index) + { + return index >= 0 && index < UnsafeNativeMethods.joyGetNumDevs(); + } + #endregion #region IJoystickDriver @@ -432,12 +437,64 @@ namespace OpenTK.Platform.Windows public GamePadCapabilities GetCapabilities(int index) { - throw new NotImplementedException(); + GamePadCapabilities gpcaps = new GamePadCapabilities(); + + if (IsValid(index)) + { + JoyCaps caps; + JoystickError result = UnsafeNativeMethods.joyGetDevCaps(index, out caps, JoyCaps.SizeInBytes); + if (result == JoystickError.NoError) + { + gpcaps.AxisCount = caps.NumAxes; + gpcaps.ButtonCount = caps.NumButtons; + if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) + gpcaps.DPadCount++; + } + } + else + { + Debug.Print("[Win] Invalid WinMM joystick device {0}", index); + } + + return gpcaps; } public GamePadState GetState(int index) { - throw new NotImplementedException(); + GamePadState state = new GamePadState(); + + if (IsValid(index)) + { + JoyInfoEx info = new JoyInfoEx(); + info.Size = JoyInfoEx.SizeInBytes; + info.Flags = JoystickFlags.All; + UnsafeNativeMethods.joyGetPosEx(index, ref info); + + state.SetAxis(GamePadAxis.LeftX, (short)info.XPos); + state.SetAxis(GamePadAxis.LeftY, (short)info.YPos); + state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); + state.SetAxis(GamePadAxis.RightY, (short)info.RPos); + //state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); + //state.SetAxis(GamePadAxis.RightY, (short)info.RPos); + + state.SetButton(Buttons.A, (info.Buttons & 1 << 0) != 0); + state.SetButton(Buttons.B, (info.Buttons & 1 << 1) != 0); + state.SetButton(Buttons.X, (info.Buttons & 1 << 2) != 0); + state.SetButton(Buttons.Y, (info.Buttons & 1 << 3) != 0); + state.SetButton(Buttons.LeftShoulder, (info.Buttons & 1 << 4) != 0); + state.SetButton(Buttons.RightShoulder, (info.Buttons & 1 << 5) != 0); + state.SetButton(Buttons.Back, (info.Buttons & 1 << 6) != 0); + state.SetButton(Buttons.Start, (info.Buttons & 1 << 7) != 0); + state.SetButton(Buttons.LeftStick, (info.Buttons & 1 << 8) != 0); + state.SetButton(Buttons.RightStick, (info.Buttons & 1 << 9) != 0); + state.SetButton(Buttons.BigButton, (info.Buttons & 1 << 10) != 0); + } + else + { + Debug.Print("[Win] Invalid WinMM joystick device {0}", index); + } + + return state; } public string GetName(int index) From d8803662085537520ef1500af0cd44735c18d6c1 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 23 Dec 2013 19:19:41 +0100 Subject: [PATCH 049/154] Enabled HIDInput IGamePadDriver implementation --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index 8e3c6011..c3e55612 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -50,7 +50,7 @@ namespace OpenTK.Platform.MacOS // Requires Mac OS X 10.5 or higher. // Todo: create a driver for older installations. Maybe use CGGetLastMouseDelta for that? - class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2/*, IGamePadDriver*/ + class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IGamePadDriver { #region Fields @@ -291,7 +291,7 @@ namespace OpenTK.Platform.MacOS public IMouseDriver2 MouseDriver { get { return this; } } public IKeyboardDriver2 KeyboardDriver { get { return this; } } - public IGamePadDriver GamePadDriver { get { throw new NotImplementedException(); } } + public IGamePadDriver GamePadDriver { get { return this; } } #endregion @@ -366,6 +366,25 @@ namespace OpenTK.Platform.MacOS #endregion + #region IGamePadDriver Members + + public GamePadState GetState(int index) + { + return new GamePadState(); + } + + public GamePadCapabilities GetCapabilities(int index) + { + return new GamePadCapabilities(); + } + + public string GetName(int index) + { + throw new NotImplementedException(); + } + + #endregion + #region NativeMethods class NativeMethods From f7e2c2ea7c8b19aac50a6c86c58e21b95d664a2c Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Mon, 23 Dec 2013 20:30:58 +0100 Subject: [PATCH 050/154] Initial implementation of GamePadTriggers --- Source/OpenTK/Input/GamePadTriggers.cs | 102 +++++++++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 1 + 2 files changed, 103 insertions(+) create mode 100644 Source/OpenTK/Input/GamePadTriggers.cs diff --git a/Source/OpenTK/Input/GamePadTriggers.cs b/Source/OpenTK/Input/GamePadTriggers.cs new file mode 100644 index 00000000..ecff49c7 --- /dev/null +++ b/Source/OpenTK/Input/GamePadTriggers.cs @@ -0,0 +1,102 @@ +// #region License +// +// GamePadTriggers.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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; + +namespace OpenTK.Input +{ + public struct GamePadTriggers : IEquatable + { + const float ConversionFactor = 1.0f / short.MaxValue; + short left; + short right; + + internal GamePadTriggers(short left, short right) + { + this.left = left; + this.right = right; + } + + #region Public Members + + public float Left + { + get { return left * ConversionFactor; } + } + + public float Right + { + get { return right * ConversionFactor; } + } + + public static bool operator ==(GamePadTriggers left, GamePadTriggers right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadTriggers left, GamePadTriggers right) + { + return !left.Equals(right); + } + + public override string ToString() + { + return String.Format( + "{{Left: {0}; Right: {1}}}", + Left, Right); + } + + public override int GetHashCode() + { + return + left.GetHashCode() ^ right.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadTriggers && + Equals((GamePadTriggers)obj); + } + + #endregion + + #region IEquatable Members + + public bool Equals(GamePadTriggers other) + { + return + left == other.left && + right == other.right; + } + + #endregion + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index aa83bbee..629191e5 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -134,6 +134,7 @@ + From 95c3d00aa27a3c8700caef58e80dc2ed3e5c66a5 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Mon, 23 Dec 2013 22:00:10 +0100 Subject: [PATCH 051/154] Refresh text continuously --- .../Examples/OpenTK/Test/GameWindowStates.cs | 67 ++++++++----------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index cc3b29b1..15be8241 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -25,9 +25,8 @@ namespace Examples.Tests int texture; bool mouse_in_window = false; bool viewport_changed = true; - bool refresh_text = true; - MouseState mouse, mouse_old; - KeyboardState keyboard, keyboard_old; + MouseState mouse; + KeyboardState keyboard; public GameWindowStates() : base(800, 600, GraphicsMode.Default) @@ -197,52 +196,40 @@ namespace Examples.Tests } protected override void OnUpdateFrame(FrameEventArgs e) - {; + { InputDriver.Poll(); mouse = OpenTK.Input.Mouse.GetState(); - if (mouse != mouse_old) - refresh_text = true; - mouse_old = mouse; - keyboard = OpenTK.Input.Keyboard.GetState(); - if (keyboard != keyboard_old) - refresh_text = true; - keyboard_old = keyboard; - if (refresh_text) + using (Graphics gfx = Graphics.FromImage(TextBitmap)) { - refresh_text = false; - - using (Graphics gfx = Graphics.FromImage(TextBitmap)) - { - int line = 0; + int line = 0; - gfx.Clear(Color.Black); - gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + gfx.Clear(Color.Black); + gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; - DrawString(gfx, GL.GetString(StringName.Vendor), line++); - DrawString(gfx, GL.GetString(StringName.Version), line++); - DrawString(gfx, GL.GetString(StringName.Renderer), line++); - DrawString(gfx, Context.GraphicsMode.ToString(), line++); + DrawString(gfx, GL.GetString(StringName.Vendor), line++); + DrawString(gfx, GL.GetString(StringName.Version), line++); + DrawString(gfx, GL.GetString(StringName.Renderer), line++); + DrawString(gfx, Context.GraphicsMode.ToString(), line++); - DrawString(gfx, String.Format("[1 - 4]: change WindowState (current: {0}).", this.WindowState), line++); - DrawString(gfx, String.Format("[5 - 7]: change WindowBorder (current: {0}).", this.WindowBorder), line++); - DrawString(gfx, String.Format("Focused: {0}.", this.Focused), line++); - DrawString(gfx, String.Format("Mouse {0} window.", mouse_in_window ? "inside" : "outside of"), line++); - DrawString(gfx, String.Format("Mouse visible: {0}", CursorVisible), line++); - DrawString(gfx, String.Format("Mouse position (absolute): {0}", new Vector3(Mouse.X, Mouse.Y, Mouse.Wheel)), line++); - DrawString(gfx, String.Format("Mouse position (relative): {0}", new Vector3(mouse.X, mouse.Y, mouse.WheelPrecise)), line++); - DrawString(gfx, String.Format("Window.Bounds: {0}", Bounds), line++); - DrawString(gfx, String.Format("Window.Location: {0}, Size: {1}", Location, Size), line++); - DrawString(gfx, String.Format("Window: {{X={0},Y={1},Width={2},Height={3}}}", X, Y, Width, Height), line++); - DrawString(gfx, String.Format("Window.ClientRectangle: {0}", ClientRectangle), line++); - DrawString(gfx, TypedText.ToString(), line++); - DrawKeyboard(gfx, keyboard, line++); - DrawMouse(gfx, mouse, line++); - line = DrawJoysticks(gfx, Joysticks, line++); - line = DrawGamePads(gfx, line++); - } + DrawString(gfx, String.Format("[1 - 4]: change WindowState (current: {0}).", this.WindowState), line++); + DrawString(gfx, String.Format("[5 - 7]: change WindowBorder (current: {0}).", this.WindowBorder), line++); + DrawString(gfx, String.Format("Focused: {0}.", this.Focused), line++); + DrawString(gfx, String.Format("Mouse {0} window.", mouse_in_window ? "inside" : "outside of"), line++); + DrawString(gfx, String.Format("Mouse visible: {0}", CursorVisible), line++); + DrawString(gfx, String.Format("Mouse position (absolute): {0}", new Vector3(Mouse.X, Mouse.Y, Mouse.Wheel)), line++); + DrawString(gfx, String.Format("Mouse position (relative): {0}", new Vector3(mouse.X, mouse.Y, mouse.WheelPrecise)), line++); + DrawString(gfx, String.Format("Window.Bounds: {0}", Bounds), line++); + DrawString(gfx, String.Format("Window.Location: {0}, Size: {1}", Location, Size), line++); + DrawString(gfx, String.Format("Window: {{X={0},Y={1},Width={2},Height={3}}}", X, Y, Width, Height), line++); + DrawString(gfx, String.Format("Window.ClientRectangle: {0}", ClientRectangle), line++); + DrawString(gfx, TypedText.ToString(), line++); + DrawKeyboard(gfx, keyboard, line++); + DrawMouse(gfx, mouse, line++); + line = DrawJoysticks(gfx, Joysticks, line++); + line = DrawGamePads(gfx, line++); } System.Drawing.Imaging.BitmapData data = TextBitmap.LockBits( From 1d84c1d814c34fcccd48b9a730eedf3f2e0220d4 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 00:15:28 +0100 Subject: [PATCH 052/154] Implemented GamePad Capabilities and Type --- Source/OpenTK/Input/GamePadCapabilities.cs | 194 ++++++++++++++++++--- Source/OpenTK/Input/GamePadType.cs | 45 +++++ Source/OpenTK/OpenTK.csproj | 1 + 3 files changed, 220 insertions(+), 20 deletions(-) create mode 100644 Source/OpenTK/Input/GamePadType.cs diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 767e0198..16707aba 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -39,28 +39,152 @@ namespace OpenTK.Input byte dpad_count; byte trackball_count; - public int AxisCount + Buttons buttons; + byte gamepad_type; + bool is_connected; + + #region Constructors + + public GamePadCapabilities(GamePadType type, Buttons buttons, bool is_connected) + : this() { - get { return axis_count; } - internal set { axis_count = (byte)value; } + gamepad_type = (byte)type; + this.buttons = buttons; + this.is_connected = is_connected; } - public int ButtonCount + #endregion + + #region Public Members + + public GamePadType GamePadType { - get { return button_count; } - internal set { button_count = (byte)value; } + get { return (GamePadType)gamepad_type; } } - public int DPadCount + public bool HasDPadUpButton { - get { return dpad_count; } - internal set { dpad_count = (byte)value; } + get { return (buttons & Buttons.DPadUp) != 0; } } - public int TrackballCount + public bool HasDPadLeftButton { - get { return trackball_count; } - internal set { trackball_count = (byte)value; } + get { return (buttons & Buttons.DPadLeft) != 0; } + } + + public bool HasDPadDownButton + { + get { return (buttons & Buttons.DPadDown) != 0; } + } + + public bool HasDPadRightButton + { + get { return (buttons & Buttons.DPadRight) != 0; } + } + + public bool HasAButton + { + get { return (buttons & Buttons.A) != 0; } + } + + public bool HasBButton + { + get { return (buttons & Buttons.B) != 0; } + } + + public bool HasXButton + { + get { return (buttons & Buttons.X) != 0; } + } + + public bool HasYButton + { + get { return (buttons & Buttons.Y) != 0; } + } + + public bool HasLeftStickButton + { + get { return (buttons & Buttons.LeftStick) != 0; } + } + + public bool HasRightStickButton + { + get { return (buttons & Buttons.RightStick) != 0; } + } + + public bool HasLeftShoulderButton + { + get { return (buttons & Buttons.LeftShoulder) != 0; } + } + + public bool HasRightShoulderButton + { + get { return (buttons & Buttons.RightShoulder) != 0; } + } + + public bool HasBackButton + { + get { return (buttons & Buttons.Back) != 0; } + } + + public bool HasBigButton + { + get { return (buttons & Buttons.BigButton) != 0; } + } + + public bool HasStartButton + { + get { return (buttons & Buttons.Start) != 0; } + } + + public bool HasLeftXThumbStick + { + get { return false; } + } + + public bool HasLeftYThumbStick + { + get { return false; } + } + + public bool HasRightXThumbStick + { + get { return false; } + } + + public bool HasRightYThumbStick + { + get { return false; } + } + + public bool HasLeftTrigger + { + get { return false; } + } + + public bool HasRightTrigger + { + get { return false; } + } + + public bool HasLeftVibrationMotor + { + get { return false; } + } + + public bool HasRightVibrationMotor + { + get { return false; } + } + + public bool HasVoiceSupport + { + get { return false; } + } + + public bool IsConnected + { + get { return is_connected; } } public static bool operator ==(GamePadCapabilities left, GamePadCapabilities right) @@ -76,15 +200,16 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Axes: {0}; Buttons: {1}; DPads: {2}; Trackballs: {3}}}", - AxisCount, ButtonCount, DPadCount, TrackballCount); + "{{Type: {0}; Buttons: {1}; Connected: {2}}}", + GamePadType, Convert.ToString((int)buttons, 2), IsConnected); } public override int GetHashCode() { return - AxisCount.GetHashCode() ^ ButtonCount.GetHashCode() ^ - DPadCount.GetHashCode() ^ TrackballCount.GetHashCode(); + buttons.GetHashCode() ^ + is_connected.GetHashCode() ^ + gamepad_type.GetHashCode(); } public override bool Equals(object obj) @@ -94,15 +219,44 @@ namespace OpenTK.Input Equals((GamePadCapabilities)obj); } + #endregion + + #region Internal Members + + internal int AxisCount + { + get { return axis_count; } + set { axis_count = (byte)value; } + } + + internal int ButtonCount + { + get { return button_count; } + set { button_count = (byte)value; } + } + + internal int DPadCount + { + get { return dpad_count; } + set { dpad_count = (byte)value; } + } + + internal int TrackballCount + { + get { return trackball_count; } + set { trackball_count = (byte)value; } + } + + #endregion + #region IEquatable Members public bool Equals(GamePadCapabilities other) { return - AxisCount == other.AxisCount && - ButtonCount == other.ButtonCount && - DPadCount == other.DPadCount && - TrackballCount == other.TrackballCount; + buttons == other.buttons && + is_connected == other.is_connected && + gamepad_type == other.gamepad_type; } #endregion diff --git a/Source/OpenTK/Input/GamePadType.cs b/Source/OpenTK/Input/GamePadType.cs new file mode 100644 index 00000000..a4eddef8 --- /dev/null +++ b/Source/OpenTK/Input/GamePadType.cs @@ -0,0 +1,45 @@ +// #region License +// +// GamePadType.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 + +namespace OpenTK.Input +{ + public enum GamePadType + { + Unknown = 0, + ArcadeStick, + DancePad, + FlightStick, + Guitar, + Wheel, + AlternateGuitar, + BigButtonPad, + DrumKit, + GamePad, + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 629191e5..81fec8c7 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -135,6 +135,7 @@ + From de362177c5d753ae6d4ee0e9deb4d621c3647ca2 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 00:15:43 +0100 Subject: [PATCH 053/154] Removed all instances of refresh_text --- Source/Examples/OpenTK/Test/GameWindowStates.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 15be8241..8359a552 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -39,20 +39,9 @@ namespace Examples.Tests MouseEnter += delegate { mouse_in_window = true; }; MouseLeave += delegate { mouse_in_window = false; }; - Move += delegate { refresh_text = true; }; - Resize += delegate { refresh_text = true; }; - WindowBorderChanged += delegate { refresh_text = true; }; - WindowStateChanged += delegate { refresh_text = true; }; - FocusedChanged += delegate { refresh_text = true; }; Mouse.Move += MouseMoveHandler; Mouse.ButtonDown += MouseButtonHandler; Mouse.ButtonUp += MouseButtonHandler; - foreach (var joystick in Joysticks) - { - joystick.Move += delegate { refresh_text = true; }; - joystick.ButtonDown += delegate { refresh_text = true; }; - joystick.ButtonUp += delegate { refresh_text = true; }; - } } private void KeyPressHandler(object sender, KeyPressEventArgs e) @@ -98,13 +87,10 @@ namespace Examples.Tests void MouseMoveHandler(object sender, MouseMoveEventArgs e) { - refresh_text = true; } void MouseButtonHandler(object sender, MouseButtonEventArgs e) { - refresh_text = true; - if (e.Button == MouseButton.Left && e.IsPressed) { CursorVisible = false; From 61e2dc3d8651a901cc9c93e180fe6c4511df44fc Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 01:36:44 +0100 Subject: [PATCH 054/154] Added missing left/right triggers --- Source/OpenTK/Input/GamePadState.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index ceec371f..22111b53 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -41,6 +41,8 @@ namespace OpenTK.Input short left_stick_y; short right_stick_x; short right_stick_y; + byte left_trigger; + byte right_trigger; bool is_connected; #region Public Members From 78078d07420377406bb06adf30f76e36687a0b10 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 01:37:34 +0100 Subject: [PATCH 055/154] Implemented initial XInput IGamePadDriver --- Source/OpenTK/OpenTK.csproj | 1 + .../OpenTK/Platform/Windows/XInputJoystick.cs | 299 ++++++++++++++++++ 2 files changed, 300 insertions(+) create mode 100644 Source/OpenTK/Platform/Windows/XInputJoystick.cs diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 81fec8c7..c7de48e4 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -158,6 +158,7 @@ + Code diff --git a/Source/OpenTK/Platform/Windows/XInputJoystick.cs b/Source/OpenTK/Platform/Windows/XInputJoystick.cs new file mode 100644 index 00000000..f3e0c04e --- /dev/null +++ b/Source/OpenTK/Platform/Windows/XInputJoystick.cs @@ -0,0 +1,299 @@ +// #region License +// +// XInputJoystick.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; +using OpenTK.Input; +using System.Runtime.InteropServices; +using System.Security; + +namespace OpenTK.Platform.Windows +{ + class XInputJoystick : IGamePadDriver + { + #region IGamePadDriver Members + + public GamePadState GetState(int index) + { + XInputState xstate; + XInput910.GetState((XInputUserIndex)index, out xstate); + + GamePadState state = new GamePadState(); + state.SetButton(Buttons.A, (xstate.GamePad.Buttons & XInputButtons.A) != 0); + state.SetButton(Buttons.B, (xstate.GamePad.Buttons & XInputButtons.B) != 0); + state.SetButton(Buttons.X, (xstate.GamePad.Buttons & XInputButtons.X) != 0); + state.SetButton(Buttons.Y, (xstate.GamePad.Buttons & XInputButtons.Y) != 0); + state.SetButton(Buttons.Start, (xstate.GamePad.Buttons & XInputButtons.Start) != 0); + state.SetButton(Buttons.Back, (xstate.GamePad.Buttons & XInputButtons.Back) != 0); + //state.SetButton(Buttons.BigButton, (xstate.GamePad.Buttons & XInputButtons.???) != 0); + state.SetButton(Buttons.LeftShoulder, (xstate.GamePad.Buttons & XInputButtons.LeftShoulder) != 0); + state.SetButton(Buttons.RightShoulder, (xstate.GamePad.Buttons & XInputButtons.RightShoulder) != 0); + state.SetButton(Buttons.LeftStick, (xstate.GamePad.Buttons & XInputButtons.LeftThumb) != 0); + state.SetButton(Buttons.RightStick, (xstate.GamePad.Buttons & XInputButtons.RightThumb) != 0); + state.SetButton(Buttons.DPadDown, (xstate.GamePad.Buttons & XInputButtons.DPadDown) != 0); + state.SetButton(Buttons.DPadUp, (xstate.GamePad.Buttons & XInputButtons.DPadUp) != 0); + state.SetButton(Buttons.DPadLeft, (xstate.GamePad.Buttons & XInputButtons.DPadLeft) != 0); + state.SetButton(Buttons.DPadRight, (xstate.GamePad.Buttons & XInputButtons.DPadRight) != 0); + + return state; + } + + public GamePadCapabilities GetCapabilities(int index) + { + throw new NotImplementedException(); + } + + public string GetName(int index) + { + throw new NotImplementedException(); + } + + #endregion + + #region Private Members + + enum XInputErrorCode + { + Success = 0, + DeviceNotConnected + } + + enum XInputType + { + GamePad + } + + enum XInputSubType + { + Unknown = 0, + GamePad = 1, + Wheel = 2, + ArcadeStick = 3, + FlightStick = 4, + DancePad = 5, + Guitar = 6, + GuitarAlternate = 7, + DrumKit = 8, + GuitarBass = 0xb, + ArcadePad = 0x13 + } + + enum XInputCapabilities + { + Ffb = 0x0001, + Wireless = 0x0002, + Voice = 0x0004, + Pmd = 0x0008, + NoNavigation = 0x0010, + } + + enum XInputButtons : ushort + { + DPadUp = 0x0001, + DPadDown = 0x0002, + DPadLeft = 0x0004, + DPadRight = 0x0008, + Start = 0x0010, + Back = 0x0020, + LeftThumb = 0x0040, + RightThumb = 0x0080, + LeftShoulder = 0x0100, + RightShoulder = 0x0200, + A = 0x1000, + B = 0x2000, + X = 0x4000, + Y = 0x8000 + } + + [Flags] + enum XInputCapabilitiesFlags + { + Default = 0, + GamePadOnly = 1 + } + + enum XInputBatteryType : byte + { + Disconnected = 0x00, + Wired = 0x01, + Alkaline = 0x02, + NiMH = 0x03, + Unknown = 0xff + } + + enum XInputBatteryLevel : byte + { + Empty = 0x00, + Low = 0x01, + Medium = 0x02, + Full = 0x03 + } + + enum XInputUserIndex + { + First = 0, + Second, + Third, + Fourth, + Any = 0xff + } + + struct XInputThresholds + { + public const int LeftThumbDeadzone = 7849; + public const int RightThumbDeadzone = 8689; + public const int TriggerThreshold = 30; + } + + struct XInputGamePad + { + public XInputButtons Buttons; + public byte LeftTrigger; + public byte RightTrigger; + public short ThumbLX; + public short ThumbLY; + public short ThumbRX; + public short ThumbRY; + } + + struct XInputState + { + public int PacketNumber; + public XInputGamePad GamePad; + } + + struct XInputVibration + { + public short LeftMotorSpeed; + public short RightMotorSpeed; + } + + struct XInputDeviceCapabilities + { + public byte Type; + public byte SubType; + public short Flags; + public XInputGamePad GamePad; + public XInputVibration Vibration; + } + + struct XInputBatteryInformation + { + public XInputBatteryType Type; + public XInputBatteryLevel Level; + } + + static class XInput910 + { + const string dll = "XINPUT9_1_0"; + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetCapabilities( + XInputUserIndex dwUserIndex, + XInputCapabilitiesFlags dwFlags, + ref XInputDeviceCapabilities pCapabilities); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetState + ( + XInputUserIndex dwUserIndex, + out XInputState pState + ); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode SetState + ( + XInputUserIndex dwUserIndex, + ref XInputVibration pVibration + ); + } + + static class XInput13 + { + const string dll = "XINPUT1_3"; + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetCapabilities( + XInputUserIndex dwUserIndex, + XInputCapabilitiesFlags dwFlags, + ref XInputDeviceCapabilities pCapabilities); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetState + ( + XInputUserIndex dwUserIndex, + out XInputState pState + ); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode SetState + ( + XInputUserIndex dwUserIndex, + ref XInputVibration pVibration + ); + } + + static class XInput14 + { + const string dll = "XINPUT1_4"; + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetCapabilities( + XInputUserIndex dwUserIndex, + XInputCapabilitiesFlags dwFlags, + ref XInputDeviceCapabilities pCapabilities); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetState + ( + XInputUserIndex dwUserIndex, + out XInputState pState + ); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode SetState + ( + XInputUserIndex dwUserIndex, + ref XInputVibration pVibration + ); + } + + #endregion + } +} From 5215891a4fbc8882aa2cf77174119d902f6f23bd Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 03:16:32 +0100 Subject: [PATCH 056/154] Added IJoystickDevice2 interface --- Source/OpenTK/Input/GamePadCapabilities.cs | 33 -------- Source/OpenTK/Input/GamePadType.cs | 4 +- Source/OpenTK/Input/IInputDriver2.cs | 1 + Source/OpenTK/Input/IJoystickDriver2.cs | 41 ++++++++++ Source/OpenTK/Input/Joystick.cs | 51 ++++++++++++ Source/OpenTK/Input/JoystickAxis.cs | 62 +++++++++++++++ Source/OpenTK/Input/JoystickButton.cs | 78 ++++++++++++++++++ Source/OpenTK/Input/JoystickCapabilities.cs | 75 ++++++++++++++++++ Source/OpenTK/Input/JoystickDevice.cs | 74 ----------------- Source/OpenTK/Input/JoystickState.cs | 79 +++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 6 ++ Source/OpenTK/Platform/Factory.cs | 10 +++ Source/OpenTK/Platform/IPlatformFactory.cs | 2 + Source/OpenTK/Platform/MacOS/CarbonInput.cs | 5 ++ Source/OpenTK/Platform/MacOS/HIDInput.cs | 20 ++++- Source/OpenTK/Platform/MacOS/MacOSFactory.cs | 5 ++ Source/OpenTK/Platform/SDL2/Sdl2Factory.cs | 5 ++ .../OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 8 ++ .../Platform/SDL2/Sdl2JoystickDriver.cs | 16 +++- Source/OpenTK/Platform/Windows/WinFactory.cs | 7 +- .../OpenTK/Platform/Windows/WinInputBase.cs | 2 + .../OpenTK/Platform/Windows/WinMMJoystick.cs | 8 +- Source/OpenTK/Platform/Windows/WinRawInput.cs | 5 ++ .../OpenTK/Platform/Windows/XInputJoystick.cs | 4 +- Source/OpenTK/Platform/X11/X11Factory.cs | 6 ++ Source/OpenTK/Platform/X11/X11Joystick.cs | 16 +++- 26 files changed, 503 insertions(+), 120 deletions(-) create mode 100644 Source/OpenTK/Input/IJoystickDriver2.cs create mode 100644 Source/OpenTK/Input/Joystick.cs create mode 100644 Source/OpenTK/Input/JoystickAxis.cs create mode 100644 Source/OpenTK/Input/JoystickButton.cs create mode 100644 Source/OpenTK/Input/JoystickCapabilities.cs create mode 100644 Source/OpenTK/Input/JoystickState.cs diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 16707aba..c637f771 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -34,11 +34,6 @@ namespace OpenTK.Input public struct GamePadCapabilities : IEquatable { - byte axis_count; - byte button_count; - byte dpad_count; - byte trackball_count; - Buttons buttons; byte gamepad_type; bool is_connected; @@ -221,34 +216,6 @@ namespace OpenTK.Input #endregion - #region Internal Members - - internal int AxisCount - { - get { return axis_count; } - set { axis_count = (byte)value; } - } - - internal int ButtonCount - { - get { return button_count; } - set { button_count = (byte)value; } - } - - internal int DPadCount - { - get { return dpad_count; } - set { dpad_count = (byte)value; } - } - - internal int TrackballCount - { - get { return trackball_count; } - set { trackball_count = (byte)value; } - } - - #endregion - #region IEquatable Members public bool Equals(GamePadCapabilities other) diff --git a/Source/OpenTK/Input/GamePadType.cs b/Source/OpenTK/Input/GamePadType.cs index a4eddef8..1524e024 100644 --- a/Source/OpenTK/Input/GamePadType.cs +++ b/Source/OpenTK/Input/GamePadType.cs @@ -1,4 +1,4 @@ -// #region License +#region License // // GamePadType.cs // @@ -25,7 +25,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // -// #endregion +#endregion namespace OpenTK.Input { diff --git a/Source/OpenTK/Input/IInputDriver2.cs b/Source/OpenTK/Input/IInputDriver2.cs index 7cd788aa..0e4c5132 100644 --- a/Source/OpenTK/Input/IInputDriver2.cs +++ b/Source/OpenTK/Input/IInputDriver2.cs @@ -37,5 +37,6 @@ namespace OpenTK.Input IMouseDriver2 MouseDriver { get; } IKeyboardDriver2 KeyboardDriver { get; } IGamePadDriver GamePadDriver { get; } + IJoystickDriver2 JoystickDriver { get; } } } diff --git a/Source/OpenTK/Input/IJoystickDriver2.cs b/Source/OpenTK/Input/IJoystickDriver2.cs new file mode 100644 index 00000000..1359d1de --- /dev/null +++ b/Source/OpenTK/Input/IJoystickDriver2.cs @@ -0,0 +1,41 @@ +#region License +// +// IJoystickDriver2.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + interface IJoystickDriver2 + { + JoystickState GetState(int index); + JoystickCapabilities GetCapabilities(int index); + } +} diff --git a/Source/OpenTK/Input/Joystick.cs b/Source/OpenTK/Input/Joystick.cs new file mode 100644 index 00000000..0458abed --- /dev/null +++ b/Source/OpenTK/Input/Joystick.cs @@ -0,0 +1,51 @@ +#region License +// +// Joystick.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + public class Joystick + { + static readonly IJoystickDriver2 implementation = + Platform.Factory.Default.CreateJoystickDriver(); + + public static JoystickCapabilities GetCapabilities(int index) + { + return implementation.GetCapabilities(index); + } + + public static JoystickState GetState(int index) + { + return implementation.GetState(index); + } + } +} diff --git a/Source/OpenTK/Input/JoystickAxis.cs b/Source/OpenTK/Input/JoystickAxis.cs new file mode 100644 index 00000000..1e166e66 --- /dev/null +++ b/Source/OpenTK/Input/JoystickAxis.cs @@ -0,0 +1,62 @@ +#region License +// +// JoystickAxis.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + /// + /// Defines available JoystickDevice axes. + /// + public enum JoystickAxis + { + /// The first axis of the JoystickDevice. + Axis0 = 0, + /// The second axis of the JoystickDevice. + Axis1, + /// The third axis of the JoystickDevice. + Axis2, + /// The fourth axis of the JoystickDevice. + Axis3, + /// The fifth axis of the JoystickDevice. + Axis4, + /// The sixth axis of the JoystickDevice. + Axis5, + /// The seventh axis of the JoystickDevice. + Axis6, + /// The eighth axis of the JoystickDevice. + Axis7, + /// The ninth axis of the JoystickDevice. + Axis8, + /// The tenth axis of the JoystickDevice. + Axis9, + } +} diff --git a/Source/OpenTK/Input/JoystickButton.cs b/Source/OpenTK/Input/JoystickButton.cs new file mode 100644 index 00000000..cf3a9ca6 --- /dev/null +++ b/Source/OpenTK/Input/JoystickButton.cs @@ -0,0 +1,78 @@ +#region License +// +// JoystickButton.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + #region JoystickButton + + /// + /// Defines available JoystickDevice buttons. + /// + public enum JoystickButton + { + /// The first button of the JoystickDevice. + Button0 = 0, + /// The second button of the JoystickDevice. + Button1, + /// The third button of the JoystickDevice. + Button2, + /// The fourth button of the JoystickDevice. + Button3, + /// The fifth button of the JoystickDevice. + Button4, + /// The sixth button of the JoystickDevice. + Button5, + /// The seventh button of the JoystickDevice. + Button6, + /// The eighth button of the JoystickDevice. + Button7, + /// The ninth button of the JoystickDevice. + Button8, + /// The tenth button of the JoystickDevice. + Button9, + /// The eleventh button of the JoystickDevice. + Button10, + /// The twelfth button of the JoystickDevice. + Button11, + /// The thirteenth button of the JoystickDevice. + Button12, + /// The fourteenth button of the JoystickDevice. + Button13, + /// The fifteenth button of the JoystickDevice. + Button14, + /// The sixteenth button of the JoystickDevice. + Button15, + } + + #endregion +} diff --git a/Source/OpenTK/Input/JoystickCapabilities.cs b/Source/OpenTK/Input/JoystickCapabilities.cs new file mode 100644 index 00000000..5265d209 --- /dev/null +++ b/Source/OpenTK/Input/JoystickCapabilities.cs @@ -0,0 +1,75 @@ +#region License +// +// JoystickCapabilities.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + public struct JoystickCapabilities + { + byte axis_count; + byte button_count; + byte dpad_count; + byte trackball_count; + + #region Public Members + + public int AxisCount + { + get { return axis_count; } + set { axis_count = (byte)value; } + } + + public int ButtonCount + { + get { return button_count; } + set { button_count = (byte)value; } + } + + #endregion + + #region Private Members + + int DPadCount + { + get { return dpad_count; } + set { dpad_count = (byte)value; } + } + + int TrackballCount + { + get { return trackball_count; } + set { trackball_count = (byte)value; } + } + + #endregion + } +} diff --git a/Source/OpenTK/Input/JoystickDevice.cs b/Source/OpenTK/Input/JoystickDevice.cs index 6f99cdac..d02d5b4c 100644 --- a/Source/OpenTK/Input/JoystickDevice.cs +++ b/Source/OpenTK/Input/JoystickDevice.cs @@ -271,49 +271,6 @@ namespace OpenTK.Input #endregion - #region JoystickButton - - /// - /// Defines available JoystickDevice buttons. - /// - public enum JoystickButton - { - /// The first button of the JoystickDevice. - Button0 = 0, - /// The second button of the JoystickDevice. - Button1, - /// The third button of the JoystickDevice. - Button2, - /// The fourth button of the JoystickDevice. - Button3, - /// The fifth button of the JoystickDevice. - Button4, - /// The sixth button of the JoystickDevice. - Button5, - /// The seventh button of the JoystickDevice. - Button6, - /// The eighth button of the JoystickDevice. - Button7, - /// The ninth button of the JoystickDevice. - Button8, - /// The tenth button of the JoystickDevice. - Button9, - /// The eleventh button of the JoystickDevice. - Button10, - /// The twelfth button of the JoystickDevice. - Button11, - /// The thirteenth button of the JoystickDevice. - Button12, - /// The fourteenth button of the JoystickDevice. - Button13, - /// The fifteenth button of the JoystickDevice. - Button14, - /// The sixteenth button of the JoystickDevice. - Button15, - } - - #endregion - #region JoystickButtonCollection /// @@ -376,37 +333,6 @@ namespace OpenTK.Input #endregion - #region JoystickAxis - - /// - /// Defines available JoystickDevice axes. - /// - public enum JoystickAxis - { - /// The first axis of the JoystickDevice. - Axis0 = 0, - /// The second axis of the JoystickDevice. - Axis1, - /// The third axis of the JoystickDevice. - Axis2, - /// The fourth axis of the JoystickDevice. - Axis3, - /// The fifth axis of the JoystickDevice. - Axis4, - /// The sixth axis of the JoystickDevice. - Axis5, - /// The seventh axis of the JoystickDevice. - Axis6, - /// The eighth axis of the JoystickDevice. - Axis7, - /// The ninth axis of the JoystickDevice. - Axis8, - /// The tenth axis of the JoystickDevice. - Axis9, - } - - #endregion - #region JoystickAxisCollection /// diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs new file mode 100644 index 00000000..28775e69 --- /dev/null +++ b/Source/OpenTK/Input/JoystickState.cs @@ -0,0 +1,79 @@ +#region License +// +// JoystickState.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Diagnostics; +using System.Text; + +namespace OpenTK.Input +{ + public struct JoystickState + { + const int MaxAxes = 10; // JoystickAxis defines 10 axes + const float ConversionFactor = 1.0f / short.MaxValue; + unsafe fixed short axes[MaxAxes]; + JoystickButton buttons; + + public float GetAxis(JoystickAxis axis) + { + return GetAxis((int)axis); + } + + public float GetAxis(int axis) + { + float value = 0.0f; + if (axis >= 0 && axis < MaxAxes) + { + unsafe + { + fixed (short* paxis = axes) + { + value = *(paxis + axis) * ConversionFactor; + } + } + } + else + { + Debug.Print("[Joystick] Invalid axis {0}", axis); + } + return value; + } + + public bool IsButtonDown(JoystickButton button) + { + return (buttons & button) != 0; + } + + public bool IsButtonUp(JoystickButton button) + { + return (buttons & button) == 0; + } + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index c7de48e4..01e5c793 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -138,8 +138,14 @@ + + + + + + diff --git a/Source/OpenTK/Platform/Factory.cs b/Source/OpenTK/Platform/Factory.cs index a3ffa951..e49eb36b 100644 --- a/Source/OpenTK/Platform/Factory.cs +++ b/Source/OpenTK/Platform/Factory.cs @@ -149,6 +149,11 @@ namespace OpenTK.Platform return default_implementation.CreateGamePadDriver(); } + public Input.IJoystickDriver2 CreateJoystickDriver() + { + return default_implementation.CreateJoystickDriver(); + } + class UnsupportedPlatform : IPlatformFactory { #region Fields @@ -210,6 +215,11 @@ namespace OpenTK.Platform throw new PlatformNotSupportedException(error_string); } + public Input.IJoystickDriver2 CreateJoystickDriver() + { + throw new PlatformNotSupportedException(error_string); + } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/IPlatformFactory.cs b/Source/OpenTK/Platform/IPlatformFactory.cs index 541c8710..c59654f3 100644 --- a/Source/OpenTK/Platform/IPlatformFactory.cs +++ b/Source/OpenTK/Platform/IPlatformFactory.cs @@ -52,5 +52,7 @@ namespace OpenTK.Platform OpenTK.Input.IMouseDriver2 CreateMouseDriver(); OpenTK.Input.IGamePadDriver CreateGamePadDriver(); + + Input.IJoystickDriver2 CreateJoystickDriver(); } } diff --git a/Source/OpenTK/Platform/MacOS/CarbonInput.cs b/Source/OpenTK/Platform/MacOS/CarbonInput.cs index 1fd65a2c..640b99b8 100644 --- a/Source/OpenTK/Platform/MacOS/CarbonInput.cs +++ b/Source/OpenTK/Platform/MacOS/CarbonInput.cs @@ -113,5 +113,10 @@ namespace OpenTK.Platform.MacOS throw new NotImplementedException(); } } + + public IJoystickDriver2 JoystickDriver + { + get { throw new NotImplementedException(); } + } } } diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index c3e55612..613d1c64 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -50,7 +50,7 @@ namespace OpenTK.Platform.MacOS // Requires Mac OS X 10.5 or higher. // Todo: create a driver for older installations. Maybe use CGGetLastMouseDelta for that? - class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IGamePadDriver + class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IGamePadDriver, IJoystickDriver2 { #region Fields @@ -93,7 +93,7 @@ namespace OpenTK.Platform.MacOS #endregion - #region Private Members + #region Private Members IOHIDManagerRef CreateHIDManager() { @@ -292,6 +292,8 @@ namespace OpenTK.Platform.MacOS public IMouseDriver2 MouseDriver { get { return this; } } public IKeyboardDriver2 KeyboardDriver { get { return this; } } public IGamePadDriver GamePadDriver { get { return this; } } + public IJoystickDriver2 JoystickDriver { get { return this; } } + #endregion @@ -385,6 +387,20 @@ namespace OpenTK.Platform.MacOS #endregion + #region IJoystickDriver2 Members + + JoystickState IJoystickDriver2.GetState(int index) + { + throw new NotImplementedException(); + } + + JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) + { + throw new NotImplementedException(); + } + + #endregion + #region NativeMethods class NativeMethods diff --git a/Source/OpenTK/Platform/MacOS/MacOSFactory.cs b/Source/OpenTK/Platform/MacOS/MacOSFactory.cs index ad540311..e7dd5f05 100644 --- a/Source/OpenTK/Platform/MacOS/MacOSFactory.cs +++ b/Source/OpenTK/Platform/MacOS/MacOSFactory.cs @@ -93,6 +93,11 @@ namespace OpenTK.Platform.MacOS { return InputDriver.GamePadDriver; } + + public IJoystickDriver2 CreateJoystickDriver() + { + return InputDriver.JoystickDriver; + } #endregion diff --git a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs index 4c39156f..b8015f6b 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs @@ -104,6 +104,11 @@ namespace OpenTK.Platform.SDL2 return InputDriver.GamePadDriver; } + public IJoystickDriver2 CreateJoystickDriver() + { + return InputDriver.JoystickDriver; + } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index 3a69be40..023af9a2 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -220,6 +220,14 @@ namespace OpenTK.Platform.SDL2 } } + public IJoystickDriver2 JoystickDriver + { + get + { + return joystick_driver; + } + } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 6c7e2728..701c38d6 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -32,7 +32,7 @@ using OpenTK.Input; namespace OpenTK.Platform.SDL2 { - class Sdl2JoystickDriver : IJoystickDriver, IGamePadDriver, IDisposable + class Sdl2JoystickDriver : IJoystickDriver, IJoystickDriver2, IGamePadDriver, IDisposable { const float RangeMultiplier = 1.0f / 32768.0f; @@ -322,6 +322,20 @@ namespace OpenTK.Platform.SDL2 #endregion + #region IJoystickDriver2 Members + + JoystickState IJoystickDriver2.GetState(int index) + { + throw new NotImplementedException(); + } + + JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) + { + throw new NotImplementedException(); + } + + #endregion + #region IDisposable Members void Dispose(bool manual) diff --git a/Source/OpenTK/Platform/Windows/WinFactory.cs b/Source/OpenTK/Platform/Windows/WinFactory.cs index 5ea1a8eb..4fa46e2e 100644 --- a/Source/OpenTK/Platform/Windows/WinFactory.cs +++ b/Source/OpenTK/Platform/Windows/WinFactory.cs @@ -130,7 +130,12 @@ namespace OpenTK.Platform.Windows { return InputDriver.GamePadDriver; } - + + public IJoystickDriver2 CreateJoystickDriver() + { + return InputDriver.JoystickDriver; + } + #endregion IInputDriver2 InputDriver diff --git a/Source/OpenTK/Platform/Windows/WinInputBase.cs b/Source/OpenTK/Platform/Windows/WinInputBase.cs index 252a6f8d..7d0865f1 100644 --- a/Source/OpenTK/Platform/Windows/WinInputBase.cs +++ b/Source/OpenTK/Platform/Windows/WinInputBase.cs @@ -164,6 +164,8 @@ namespace OpenTK.Platform.Windows public abstract IKeyboardDriver2 KeyboardDriver { get; } public abstract IGamePadDriver GamePadDriver { get; } + public abstract IJoystickDriver2 JoystickDriver { get; } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 07c208cc..e7c71541 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -445,10 +445,10 @@ namespace OpenTK.Platform.Windows JoystickError result = UnsafeNativeMethods.joyGetDevCaps(index, out caps, JoyCaps.SizeInBytes); if (result == JoystickError.NoError) { - gpcaps.AxisCount = caps.NumAxes; - gpcaps.ButtonCount = caps.NumButtons; - if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) - gpcaps.DPadCount++; + //gpcaps.AxisCount = caps.NumAxes; + //gpcaps.ButtonCount = caps.NumButtons; + //if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) + // gpcaps.DPadCount++; } } else diff --git a/Source/OpenTK/Platform/Windows/WinRawInput.cs b/Source/OpenTK/Platform/Windows/WinRawInput.cs index c905b65b..04025efd 100644 --- a/Source/OpenTK/Platform/Windows/WinRawInput.cs +++ b/Source/OpenTK/Platform/Windows/WinRawInput.cs @@ -190,6 +190,11 @@ namespace OpenTK.Platform.Windows get { return joystick_driver; } } + public override IJoystickDriver2 JoystickDriver + { + get { throw new NotImplementedException(); } + } + #endregion } } diff --git a/Source/OpenTK/Platform/Windows/XInputJoystick.cs b/Source/OpenTK/Platform/Windows/XInputJoystick.cs index f3e0c04e..c6d7def1 100644 --- a/Source/OpenTK/Platform/Windows/XInputJoystick.cs +++ b/Source/OpenTK/Platform/Windows/XInputJoystick.cs @@ -1,4 +1,4 @@ -// #region License +#region License // // XInputJoystick.cs // @@ -25,7 +25,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // -// #endregion +#endregion using System; using System.Collections.Generic; diff --git a/Source/OpenTK/Platform/X11/X11Factory.cs b/Source/OpenTK/Platform/X11/X11Factory.cs index 8b8344df..0fb80058 100644 --- a/Source/OpenTK/Platform/X11/X11Factory.cs +++ b/Source/OpenTK/Platform/X11/X11Factory.cs @@ -98,6 +98,12 @@ namespace OpenTK.Platform.X11 return new X11Joystick(); } + public virtual OpenTK.Input.IJoystickDriver2 CreateJoystickDriver() + { + return new X11Joystick(); + } + + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs index b4948169..36fac9f2 100644 --- a/Source/OpenTK/Platform/X11/X11Joystick.cs +++ b/Source/OpenTK/Platform/X11/X11Joystick.cs @@ -36,7 +36,7 @@ namespace OpenTK.Platform.X11 { struct X11JoyDetails { } - sealed class X11Joystick : IJoystickDriver, IGamePadDriver + sealed class X11Joystick : IJoystickDriver, IJoystickDriver2, IGamePadDriver { #region Fields @@ -277,5 +277,19 @@ namespace OpenTK.Platform.X11 } #endregion + + #region IJoystickDriver2 Members + + JoystickState IJoystickDriver2.GetState(int index) + { + throw new NotImplementedException(); + } + + JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) + { + throw new NotImplementedException(); + } + + #endregion } } From 25a0e552f8f8c10a2e94427eac499aa5cf19552b Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 12:47:09 +0100 Subject: [PATCH 057/154] Implemented thumbsticks and trigger caps --- .../Input/{GamePadAxis.cs => GamePadAxes.cs} | 13 +- Source/OpenTK/Input/GamePadCapabilities.cs | 23 +- Source/OpenTK/Input/GamePadState.cs | 23 +- Source/OpenTK/Input/GamePadType.cs | 2 + .../Platform/SDL2/Sdl2JoystickDriver.cs | 2 +- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 8 +- .../OpenTK/Platform/Windows/XInputJoystick.cs | 267 ++++++++++++------ 7 files changed, 230 insertions(+), 108 deletions(-) rename Source/OpenTK/Input/{GamePadAxis.cs => GamePadAxes.cs} (85%) diff --git a/Source/OpenTK/Input/GamePadAxis.cs b/Source/OpenTK/Input/GamePadAxes.cs similarity index 85% rename from Source/OpenTK/Input/GamePadAxis.cs rename to Source/OpenTK/Input/GamePadAxes.cs index f619ab6a..3ddea306 100644 --- a/Source/OpenTK/Input/GamePadAxis.cs +++ b/Source/OpenTK/Input/GamePadAxes.cs @@ -27,12 +27,15 @@ using System; namespace OpenTK.Input { - internal enum GamePadAxis + [Flags] + internal enum GamePadAxes : byte { - LeftX, - LeftY, - RightX, - RightY + LeftX = 1 << 0, + LeftY = 1 << 1, + LeftTrigger = 1 << 2, + RightX = 1 << 3, + RightY = 1 << 4, + RightTrigger = 1 << 5, } } diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index c637f771..2db7b612 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -35,15 +35,17 @@ namespace OpenTK.Input public struct GamePadCapabilities : IEquatable { Buttons buttons; + GamePadAxes axes; byte gamepad_type; bool is_connected; #region Constructors - public GamePadCapabilities(GamePadType type, Buttons buttons, bool is_connected) + internal GamePadCapabilities(GamePadType type, GamePadAxes axes, Buttons buttons, bool is_connected) : this() { gamepad_type = (byte)type; + this.axes = axes; this.buttons = buttons; this.is_connected = is_connected; } @@ -134,32 +136,32 @@ namespace OpenTK.Input public bool HasLeftXThumbStick { - get { return false; } + get { return (axes & GamePadAxes.LeftX) != 0; } } public bool HasLeftYThumbStick { - get { return false; } + get { return (axes & GamePadAxes.LeftY) != 0; } } public bool HasRightXThumbStick { - get { return false; } + get { return (axes & GamePadAxes.RightX) != 0; } } public bool HasRightYThumbStick { - get { return false; } + get { return (axes & GamePadAxes.RightY) != 0; } } public bool HasLeftTrigger { - get { return false; } + get { return (axes & GamePadAxes.LeftTrigger) != 0; } } public bool HasRightTrigger { - get { return false; } + get { return (axes & GamePadAxes.RightTrigger) != 0; } } public bool HasLeftVibrationMotor @@ -195,8 +197,11 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Type: {0}; Buttons: {1}; Connected: {2}}}", - GamePadType, Convert.ToString((int)buttons, 2), IsConnected); + "{{Type: {0}; Axes: {1}; Buttons: {2}; Connected: {3}}}", + GamePadType, + Convert.ToString((int)axes, 2), + Convert.ToString((int)buttons, 2), + IsConnected); } public override int GetHashCode() diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index 22111b53..bd196982 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -62,6 +62,11 @@ namespace OpenTK.Input get { return new GamePadDPad(buttons); } } + public GamePadTriggers Triggers + { + get { return new GamePadTriggers(left_trigger, right_trigger); } + } + public bool IsConnected { get { return is_connected; } @@ -104,23 +109,23 @@ namespace OpenTK.Input #region Internal Members - internal void SetAxis(GamePadAxis axis, short value) + internal void SetAxis(GamePadAxes axis, short value) { switch (axis) { - case GamePadAxis.LeftX: + case GamePadAxes.LeftX: left_stick_x = value; break; - case GamePadAxis.LeftY: + case GamePadAxes.LeftY: left_stick_y = value; break; - case GamePadAxis.RightX: + case GamePadAxes.RightX: right_stick_x = value; break; - case GamePadAxis.RightY: + case GamePadAxes.RightY: right_stick_y = value; break; @@ -146,11 +151,17 @@ namespace OpenTK.Input is_connected = connected; } + internal void SetTriggers(byte left, byte right) + { + left_trigger = left; + right_trigger = right; + } + #endregion #region Private Members - bool IsAxisValid(GamePadAxis axis) + bool IsAxisValid(GamePadAxes axis) { int index = (int)axis; return index >= 0 && index < GamePad.MaxAxisCount; diff --git a/Source/OpenTK/Input/GamePadType.cs b/Source/OpenTK/Input/GamePadType.cs index 1524e024..37311627 100644 --- a/Source/OpenTK/Input/GamePadType.cs +++ b/Source/OpenTK/Input/GamePadType.cs @@ -41,5 +41,7 @@ namespace OpenTK.Input BigButtonPad, DrumKit, GamePad, + ArcadePad, + BassGuitar, } } diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 701c38d6..d5caa2c1 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -258,7 +258,7 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsControllerValid(id)) { - controllers[id].State.SetAxis((GamePadAxis)ev.Axis, ev.Value); + controllers[id].State.SetAxis((GamePadAxes)ev.Axis, ev.Value); } else { diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index e7c71541..1821b136 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -470,10 +470,10 @@ namespace OpenTK.Platform.Windows info.Flags = JoystickFlags.All; UnsafeNativeMethods.joyGetPosEx(index, ref info); - state.SetAxis(GamePadAxis.LeftX, (short)info.XPos); - state.SetAxis(GamePadAxis.LeftY, (short)info.YPos); - state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); - state.SetAxis(GamePadAxis.RightY, (short)info.RPos); + state.SetAxis(GamePadAxes.LeftX, (short)info.XPos); + state.SetAxis(GamePadAxes.LeftY, (short)info.YPos); + state.SetAxis(GamePadAxes.RightX, (short)info.ZPos); + state.SetAxis(GamePadAxes.RightY, (short)info.RPos); //state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); //state.SetAxis(GamePadAxis.RightY, (short)info.RPos); diff --git a/Source/OpenTK/Platform/Windows/XInputJoystick.cs b/Source/OpenTK/Platform/Windows/XInputJoystick.cs index c6d7def1..23710df0 100644 --- a/Source/OpenTK/Platform/Windows/XInputJoystick.cs +++ b/Source/OpenTK/Platform/Windows/XInputJoystick.cs @@ -33,41 +33,56 @@ using System.Text; using OpenTK.Input; using System.Runtime.InteropServices; using System.Security; +using System.Diagnostics; namespace OpenTK.Platform.Windows { - class XInputJoystick : IGamePadDriver + class XInputJoystick : IGamePadDriver, IDisposable { + XInput xinput = new XInput(); + #region IGamePadDriver Members public GamePadState GetState(int index) { XInputState xstate; - XInput910.GetState((XInputUserIndex)index, out xstate); + XInputErrorCode error = xinput.GetState((XInputUserIndex)index, out xstate); GamePadState state = new GamePadState(); - state.SetButton(Buttons.A, (xstate.GamePad.Buttons & XInputButtons.A) != 0); - state.SetButton(Buttons.B, (xstate.GamePad.Buttons & XInputButtons.B) != 0); - state.SetButton(Buttons.X, (xstate.GamePad.Buttons & XInputButtons.X) != 0); - state.SetButton(Buttons.Y, (xstate.GamePad.Buttons & XInputButtons.Y) != 0); - state.SetButton(Buttons.Start, (xstate.GamePad.Buttons & XInputButtons.Start) != 0); - state.SetButton(Buttons.Back, (xstate.GamePad.Buttons & XInputButtons.Back) != 0); - //state.SetButton(Buttons.BigButton, (xstate.GamePad.Buttons & XInputButtons.???) != 0); - state.SetButton(Buttons.LeftShoulder, (xstate.GamePad.Buttons & XInputButtons.LeftShoulder) != 0); - state.SetButton(Buttons.RightShoulder, (xstate.GamePad.Buttons & XInputButtons.RightShoulder) != 0); - state.SetButton(Buttons.LeftStick, (xstate.GamePad.Buttons & XInputButtons.LeftThumb) != 0); - state.SetButton(Buttons.RightStick, (xstate.GamePad.Buttons & XInputButtons.RightThumb) != 0); - state.SetButton(Buttons.DPadDown, (xstate.GamePad.Buttons & XInputButtons.DPadDown) != 0); - state.SetButton(Buttons.DPadUp, (xstate.GamePad.Buttons & XInputButtons.DPadUp) != 0); - state.SetButton(Buttons.DPadLeft, (xstate.GamePad.Buttons & XInputButtons.DPadLeft) != 0); - state.SetButton(Buttons.DPadRight, (xstate.GamePad.Buttons & XInputButtons.DPadRight) != 0); + if (error == XInputErrorCode.Success) + { + state.SetConnected(true); + + state.SetAxis(GamePadAxes.LeftX, xstate.GamePad.ThumbLX); + state.SetAxis(GamePadAxes.LeftY, xstate.GamePad.ThumbLY); + state.SetAxis(GamePadAxes.RightX, xstate.GamePad.ThumbRX); + state.SetAxis(GamePadAxes.RightY, xstate.GamePad.ThumbRY); + + state.SetTriggers(xstate.GamePad.LeftTrigger, xstate.GamePad.RightTrigger); + + state.SetButton(TranslateButtons(xstate.GamePad.Buttons), true); + } return state; } public GamePadCapabilities GetCapabilities(int index) { - throw new NotImplementedException(); + XInputDeviceCapabilities xcaps; + XInputErrorCode error = xinput.GetCapabilities( + (XInputUserIndex)index, + XInputCapabilitiesFlags.Default, + out xcaps); + + if (error == XInputErrorCode.Success) + { + GamePadType type = TranslateSubType(xcaps.SubType); + Buttons buttons = TranslateButtons(xcaps.GamePad.Buttons); + GamePadAxes axes = TranslateAxes(ref xcaps.GamePad); + + return new GamePadCapabilities(type, axes, buttons, true); + } + return new GamePadCapabilities(); } public string GetName(int index) @@ -78,6 +93,58 @@ namespace OpenTK.Platform.Windows #endregion #region Private Members + GamePadAxes TranslateAxes(ref XInputGamePad pad) + { + GamePadAxes axes = 0; + axes |= pad.ThumbLX != 0 ? GamePadAxes.LeftX : 0; + axes |= pad.ThumbLY != 0 ? GamePadAxes.LeftY : 0; + axes |= pad.LeftTrigger != 0 ? GamePadAxes.LeftTrigger : 0; + axes |= pad.ThumbRX != 0 ? GamePadAxes.RightX : 0; + axes |= pad.ThumbRY != 0 ? GamePadAxes.RightY : 0; + axes |= pad.RightTrigger != 0 ? GamePadAxes.RightTrigger : 0; + return axes; + } + + Buttons TranslateButtons(XInputButtons xbuttons) + { + Buttons buttons = 0; + buttons |= (xbuttons & XInputButtons.A) != 0 ? Buttons.A : 0; + buttons |= (xbuttons & XInputButtons.B) != 0 ? Buttons.B : 0; + buttons |= (xbuttons & XInputButtons.X) != 0 ? Buttons.X : 0; + buttons |= (xbuttons & XInputButtons.Y) != 0 ? Buttons.Y : 0; + buttons |= (xbuttons & XInputButtons.Start) != 0 ? Buttons.Start : 0; + buttons |= (xbuttons & XInputButtons.Back) != 0 ? Buttons.Back : 0; + //buttons |= (xbuttons & XInputButtons.BigButton) != 0 ? Buttons.BigButton : 0; + buttons |= (xbuttons & XInputButtons.LeftShoulder) != 0 ? Buttons.LeftShoulder : 0; + buttons |= (xbuttons & XInputButtons.RightShoulder) != 0 ? Buttons.RightShoulder : 0; + buttons |= (xbuttons & XInputButtons.LeftThumb) != 0 ? Buttons.LeftStick : 0; + buttons |= (xbuttons & XInputButtons.RightThumb) != 0 ? Buttons.RightStick : 0; + buttons |= (xbuttons & XInputButtons.DPadDown) != 0 ? Buttons.DPadDown : 0; + buttons |= (xbuttons & XInputButtons.DPadUp) != 0 ? Buttons.DPadUp : 0; + buttons |= (xbuttons & XInputButtons.DPadLeft) != 0 ? Buttons.DPadLeft : 0; + buttons |= (xbuttons & XInputButtons.DPadRight) != 0 ? Buttons.DPadRight : 0; + return buttons; + } + + GamePadType TranslateSubType(XInputDeviceSubType xtype) + { + switch (xtype) + { + case XInputDeviceSubType.ArcadePad: return GamePadType.ArcadePad; + case XInputDeviceSubType.ArcadeStick: return GamePadType.ArcadeStick; + case XInputDeviceSubType.DancePad: return GamePadType.DancePad; + case XInputDeviceSubType.DrumKit: return GamePadType.DrumKit; + case XInputDeviceSubType.FlightStick: return GamePadType.FlightStick; + case XInputDeviceSubType.GamePad: return GamePadType.GamePad; + case XInputDeviceSubType.Guitar: return GamePadType.Guitar; + case XInputDeviceSubType.GuitarAlternate: return GamePadType.AlternateGuitar; + case XInputDeviceSubType.GuitarBass: return GamePadType.BassGuitar; + case XInputDeviceSubType.Wheel: return GamePadType.Wheel; + case XInputDeviceSubType.Unknown: + default: + return GamePadType.Unknown; + } + } enum XInputErrorCode { @@ -85,12 +152,12 @@ namespace OpenTK.Platform.Windows DeviceNotConnected } - enum XInputType + enum XInputDeviceType : byte { GamePad } - enum XInputSubType + enum XInputDeviceSubType : byte { Unknown = 0, GamePad = 1, @@ -107,10 +174,10 @@ namespace OpenTK.Platform.Windows enum XInputCapabilities { - Ffb = 0x0001, + ForceFeedback = 0x0001, Wireless = 0x0002, Voice = 0x0004, - Pmd = 0x0008, + PluginModules = 0x0008, NoNavigation = 0x0010, } @@ -197,8 +264,8 @@ namespace OpenTK.Platform.Windows struct XInputDeviceCapabilities { - public byte Type; - public byte SubType; + public XInputDeviceType Type; + public XInputDeviceSubType SubType; public short Flags; public XInputGamePad GamePad; public XInputVibration Vibration; @@ -210,90 +277,124 @@ namespace OpenTK.Platform.Windows public XInputBatteryLevel Level; } - static class XInput910 + class XInput : IDisposable { - const string dll = "XINPUT9_1_0"; + IntPtr dll; + + internal XInput() + { + // Try to load the newest XInput***.dll installed on the system + // The delegates below will be loaded dynamically from that dll + dll = Functions.LoadLibrary("XINPUT1_4"); + if (dll == IntPtr.Zero) + dll = Functions.LoadLibrary("XINPUT1_3"); + if (dll == IntPtr.Zero) + dll = Functions.LoadLibrary("XINPUT1_2"); + if (dll == IntPtr.Zero) + dll = Functions.LoadLibrary("XINPUT1_1"); + if (dll == IntPtr.Zero) + dll = Functions.LoadLibrary("XINPUT9_1_0"); + if (dll == IntPtr.Zero) + throw new NotSupportedException("XInput was not found on this platform"); + + // Load the entry points we are interested in from that dll + GetCapabilities = (XInputGetCapabilities)Load("XInputGetCapabilities", typeof(XInputGetCapabilities)); + GetState = (XInputGetState)Load("XInputGetState", typeof(XInputGetState)); + SetState = (XInputSetState)Load("XInputSetState", typeof(XInputSetState)); + } + + #region Private Members + + Delegate Load(string name, Type type) + { + IntPtr pfunc = Functions.GetProcAddress(dll, name); + if (pfunc != IntPtr.Zero) + return Marshal.GetDelegateForFunctionPointer(pfunc, type); + return null; + } + + #endregion + + #region Internal Members + + internal XInputGetCapabilities GetCapabilities; + internal XInputGetState GetState; + internal XInputSetState SetState; [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetCapabilities( + internal delegate XInputErrorCode XInputGetCapabilities( XInputUserIndex dwUserIndex, XInputCapabilitiesFlags dwFlags, - ref XInputDeviceCapabilities pCapabilities); + out XInputDeviceCapabilities pCapabilities); [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetState + internal delegate XInputErrorCode XInputGetState ( XInputUserIndex dwUserIndex, out XInputState pState ); [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode SetState + internal delegate XInputErrorCode XInputSetState ( XInputUserIndex dwUserIndex, ref XInputVibration pVibration ); + + #endregion + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool manual) + { + if (manual) + { + if (dll != IntPtr.Zero) + { + Functions.FreeLibrary(dll); + dll = IntPtr.Zero; + } + } + } + + #endregion } - static class XInput13 + #endregion + + #region IDisposable Members + + public void Dispose() { - const string dll = "XINPUT1_3"; - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetCapabilities( - XInputUserIndex dwUserIndex, - XInputCapabilitiesFlags dwFlags, - ref XInputDeviceCapabilities pCapabilities); - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetState - ( - XInputUserIndex dwUserIndex, - out XInputState pState - ); - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode SetState - ( - XInputUserIndex dwUserIndex, - ref XInputVibration pVibration - ); + Dispose(true); + GC.SuppressFinalize(this); } - static class XInput14 + void Dispose(bool manual) { - const string dll = "XINPUT1_4"; - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetCapabilities( - XInputUserIndex dwUserIndex, - XInputCapabilitiesFlags dwFlags, - ref XInputDeviceCapabilities pCapabilities); - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetState - ( - XInputUserIndex dwUserIndex, - out XInputState pState - ); - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode SetState - ( - XInputUserIndex dwUserIndex, - ref XInputVibration pVibration - ); + if (manual) + { + xinput.Dispose(); + } + else + { + Debug.Print("{0} leaked, did you forget to call Dispose()?", typeof(XInputJoystick).Name); + } } +#if DEBUG + ~XInputJoystick() + { + Dispose(false); + } +#endif + #endregion } } From dfd65540614149acc0d0ee52e0e22915a806174f Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 12:48:15 +0100 Subject: [PATCH 058/154] Added internal GamePadMapping class --- Source/OpenTK/Input/GamePadMapping.cs | 39 +++++++++++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 3 ++- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 Source/OpenTK/Input/GamePadMapping.cs diff --git a/Source/OpenTK/Input/GamePadMapping.cs b/Source/OpenTK/Input/GamePadMapping.cs new file mode 100644 index 00000000..9ddca29f --- /dev/null +++ b/Source/OpenTK/Input/GamePadMapping.cs @@ -0,0 +1,39 @@ +#region License +// +// GamePadMapping.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + class GamePadMapping + { + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 01e5c793..be7ac936 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -133,6 +133,7 @@ + @@ -748,7 +749,7 @@ - + From 58b67d31e3e6243f767c47952a1ae9739912b06e Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 12:52:57 +0100 Subject: [PATCH 059/154] No reason to comment out #region License --- Source/OpenTK/Input/GamePadCapabilities.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 2db7b612..7fbe8055 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -1,4 +1,4 @@ -// #region License +#region License // // GamePadCapabilities.cs // @@ -25,7 +25,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // -// #endregion +#endregion using System; From 5c73a3ea74f72cc618192fd73cbc890204e1321c Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 14:21:37 +0100 Subject: [PATCH 060/154] Implements JoystickState and Capabilities setters --- Source/OpenTK/Input/JoystickCapabilities.cs | 34 ++++++++--- Source/OpenTK/Input/JoystickState.cs | 67 +++++++++++++++++++-- 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/Source/OpenTK/Input/JoystickCapabilities.cs b/Source/OpenTK/Input/JoystickCapabilities.cs index 5265d209..b25fa69b 100644 --- a/Source/OpenTK/Input/JoystickCapabilities.cs +++ b/Source/OpenTK/Input/JoystickCapabilities.cs @@ -38,20 +38,35 @@ namespace OpenTK.Input byte axis_count; byte button_count; byte dpad_count; - byte trackball_count; + bool is_connected; + + #region Constructors + + public JoystickCapabilities(int axis_count, int button_count, bool is_connected) + { + if (axis_count < 0 || axis_count >= JoystickState.MaxAxes) + throw new ArgumentOutOfRangeException("axis_count"); + if (button_count < 0 || button_count >= JoystickState.MaxButtons) + throw new ArgumentOutOfRangeException("axis_count"); + + this.axis_count = (byte)axis_count; + this.button_count = (byte)button_count; + this.dpad_count = 0; // Todo: either remove dpad_count or add it as a parameter + this.is_connected = is_connected; + } + + #endregion #region Public Members public int AxisCount { get { return axis_count; } - set { axis_count = (byte)value; } } public int ButtonCount { get { return button_count; } - set { button_count = (byte)value; } } #endregion @@ -61,15 +76,14 @@ namespace OpenTK.Input int DPadCount { get { return dpad_count; } - set { dpad_count = (byte)value; } - } - - int TrackballCount - { - get { return trackball_count; } - set { trackball_count = (byte)value; } } #endregion + + public bool IsConnected + { + get { return is_connected; } + } + } } diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index 28775e69..8a233df6 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -36,10 +36,18 @@ namespace OpenTK.Input { public struct JoystickState { - const int MaxAxes = 10; // JoystickAxis defines 10 axes - const float ConversionFactor = 1.0f / short.MaxValue; + // If we ever add more values to JoystickAxis or JoystickButton + // then we'll need to increase these limits. + internal const int MaxAxes = 10; + internal const int MaxButtons = 32; + + const float ConversionFactor = 1.0f / (short.MaxValue + 1); + unsafe fixed short axes[MaxAxes]; - JoystickButton buttons; + int buttons; + bool is_connected; + + #region Public Members public float GetAxis(JoystickAxis axis) { @@ -66,14 +74,63 @@ namespace OpenTK.Input return value; } + public ButtonState GetButton(JoystickButton button) + { + return (buttons & (1 << (int)button)) != 0 ? ButtonState.Pressed : ButtonState.Released; + } + public bool IsButtonDown(JoystickButton button) { - return (buttons & button) != 0; + return (buttons & (1 << (int)button)) != 0; } public bool IsButtonUp(JoystickButton button) { - return (buttons & button) == 0; + return (buttons & (1 << (int)button)) == 0; } + + public bool IsConnected + { + get { return is_connected; } + } + + #endregion + + #region Internal Members + + internal void SetAxis(JoystickAxis axis, short value) + { + int index = (int)axis; + if (index < 0 || index >= MaxAxes) + throw new ArgumentOutOfRangeException("axis"); + + unsafe + { + fixed (short* paxes = axes) + { + *(paxes + index) = value; + } + } + } + + internal void SetButton(JoystickButton button, bool value) + { + int index = 1 << (int)button; + if (value) + { + buttons |= index; + } + else + { + buttons &= ~index; + } + } + + internal void SetIsConnected(bool value) + { + is_connected = value; + } + + #endregion } } From b9242c006b2e55fa293135d88fc00aef0056f9b0 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 14:22:03 +0100 Subject: [PATCH 061/154] Added MappedGamePadDriver skeleton implementation --- Source/OpenTK/OpenTK.csproj | 1 + Source/OpenTK/Platform/MappedGamePadDriver.cs | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 Source/OpenTK/Platform/MappedGamePadDriver.cs diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index be7ac936..a378e483 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -164,6 +164,7 @@ + diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs new file mode 100644 index 00000000..346be196 --- /dev/null +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -0,0 +1,83 @@ +#region License +// +// MappedGamePadDriver.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; +using OpenTK.Input; + +namespace OpenTK.Platform +{ + /// \internal + /// + /// Implements IGamePadDriver using OpenTK.Input.Joystick + /// and a gamepad-specific axis/button mapping. + /// + /// + /// + /// This class supports OpenTK and is not meant to be accessed by user code. + /// + /// + /// To support gamepads on platforms that do not offer a gamepad-optimized API, + /// we need to use the generic OpenTK.Input.Joystick and implement a custom + /// mapping scheme to provide a stable mapping to OpenTK.Input.GamePad. This + /// class implements this mapping scheme. + /// + /// + class MappedGamePadDriver : IGamePadDriver + { + public GamePadState GetState(int index) + { + JoystickState joy = Joystick.GetState(index); + GamePadState pad = new GamePadState(); + if (joy.IsConnected) + { + GamePadMapping mapping = new GamePadMapping();//GamePadMapping.Lookup() + // Todo: implement mapping + } + return pad; + } + + public GamePadCapabilities GetCapabilities(int index) + { + JoystickCapabilities joy = Joystick.GetCapabilities(index); + GamePadCapabilities pad = new GamePadCapabilities(); + if (joy.IsConnected) + { + // Todo: implement mapping + } + return pad; + } + + public string GetName(int index) + { + throw new NotImplementedException(); + } + } +} From 062962aeb2b45c852550cd670d85193529dd4749 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 14:24:29 +0100 Subject: [PATCH 062/154] WinMMJoystick implements IJoystickDriver2 WinMM is optimized for general joystick use, not for the canonical GamePad layout. Instead of exposing IGamePadDriver directly, it should expose IJoystickDriver2 and use a mapping driver to get GamePad support. --- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 131 ++++++++---------- 1 file changed, 59 insertions(+), 72 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 1821b136..882ce5f0 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -36,7 +36,7 @@ using System.Diagnostics; namespace OpenTK.Platform.Windows { - sealed class WinMMJoystick : IJoystickDriver, IGamePadDriver + sealed class WinMMJoystick : IJoystickDriver, IJoystickDriver2 { #region Fields @@ -242,6 +242,64 @@ namespace OpenTK.Platform.Windows #endregion + #region IJoystickDriver2 Members + + public JoystickCapabilities GetCapabilities(int index) + { + if (IsValid(index)) + { + JoyCaps mmcaps; + JoystickError result = UnsafeNativeMethods.joyGetDevCaps(index, out mmcaps, JoyCaps.SizeInBytes); + if (result == JoystickError.NoError) + { + JoystickCapabilities caps = new JoystickCapabilities( + mmcaps.NumAxes, mmcaps.NumButtons, true); + //if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) + // gpcaps.DPadCount++; + return caps; + } + } + else + { + Debug.Print("[Win] Invalid WinMM joystick device {0}", index); + } + + return new JoystickCapabilities(); + } + + public JoystickState GetState(int index) + { + JoystickState state = new JoystickState(); + + if (IsValid(index)) + { + JoyInfoEx info = new JoyInfoEx(); + info.Size = JoyInfoEx.SizeInBytes; + info.Flags = JoystickFlags.All; + UnsafeNativeMethods.joyGetPosEx(index, ref info); + + state.SetAxis(JoystickAxis.Axis0, (short)info.XPos); + state.SetAxis(JoystickAxis.Axis1, (short)info.YPos); + state.SetAxis(JoystickAxis.Axis2, (short)info.ZPos); + state.SetAxis(JoystickAxis.Axis3, (short)info.RPos); + state.SetAxis(JoystickAxis.Axis4, (short)info.ZPos); + state.SetAxis(JoystickAxis.Axis5, (short)info.RPos); + + for (int i = 0; i < 16; i++) + { + state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); + } + } + else + { + Debug.Print("[Win] Invalid WinMM joystick device {0}", index); + } + + return state; + } + + #endregion + #region IDisposable public void Dispose() @@ -432,76 +490,5 @@ namespace OpenTK.Platform.Windows } #endregion - - #region IGamePadDriver Members - - public GamePadCapabilities GetCapabilities(int index) - { - GamePadCapabilities gpcaps = new GamePadCapabilities(); - - if (IsValid(index)) - { - JoyCaps caps; - JoystickError result = UnsafeNativeMethods.joyGetDevCaps(index, out caps, JoyCaps.SizeInBytes); - if (result == JoystickError.NoError) - { - //gpcaps.AxisCount = caps.NumAxes; - //gpcaps.ButtonCount = caps.NumButtons; - //if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) - // gpcaps.DPadCount++; - } - } - else - { - Debug.Print("[Win] Invalid WinMM joystick device {0}", index); - } - - return gpcaps; - } - - public GamePadState GetState(int index) - { - GamePadState state = new GamePadState(); - - if (IsValid(index)) - { - JoyInfoEx info = new JoyInfoEx(); - info.Size = JoyInfoEx.SizeInBytes; - info.Flags = JoystickFlags.All; - UnsafeNativeMethods.joyGetPosEx(index, ref info); - - state.SetAxis(GamePadAxes.LeftX, (short)info.XPos); - state.SetAxis(GamePadAxes.LeftY, (short)info.YPos); - state.SetAxis(GamePadAxes.RightX, (short)info.ZPos); - state.SetAxis(GamePadAxes.RightY, (short)info.RPos); - //state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); - //state.SetAxis(GamePadAxis.RightY, (short)info.RPos); - - state.SetButton(Buttons.A, (info.Buttons & 1 << 0) != 0); - state.SetButton(Buttons.B, (info.Buttons & 1 << 1) != 0); - state.SetButton(Buttons.X, (info.Buttons & 1 << 2) != 0); - state.SetButton(Buttons.Y, (info.Buttons & 1 << 3) != 0); - state.SetButton(Buttons.LeftShoulder, (info.Buttons & 1 << 4) != 0); - state.SetButton(Buttons.RightShoulder, (info.Buttons & 1 << 5) != 0); - state.SetButton(Buttons.Back, (info.Buttons & 1 << 6) != 0); - state.SetButton(Buttons.Start, (info.Buttons & 1 << 7) != 0); - state.SetButton(Buttons.LeftStick, (info.Buttons & 1 << 8) != 0); - state.SetButton(Buttons.RightStick, (info.Buttons & 1 << 9) != 0); - state.SetButton(Buttons.BigButton, (info.Buttons & 1 << 10) != 0); - } - else - { - Debug.Print("[Win] Invalid WinMM joystick device {0}", index); - } - - return state; - } - - public string GetName(int index) - { - throw new NotImplementedException(); - } - - #endregion } } From 42e6a96a4340f0c7ac27fff7cfd23d65cc849587 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 14:24:42 +0100 Subject: [PATCH 063/154] Connected XInput driver --- Source/OpenTK/Platform/Windows/WinRawInput.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinRawInput.cs b/Source/OpenTK/Platform/Windows/WinRawInput.cs index 04025efd..08e57201 100644 --- a/Source/OpenTK/Platform/Windows/WinRawInput.cs +++ b/Source/OpenTK/Platform/Windows/WinRawInput.cs @@ -43,7 +43,8 @@ namespace OpenTK.Platform.Windows WinRawKeyboard keyboard_driver; WinRawMouse mouse_driver; - WinMMJoystick joystick_driver; + IGamePadDriver gamepad_driver; + IJoystickDriver2 joystick_driver; IntPtr DevNotifyHandle; static readonly Guid DeviceInterfaceHid = new Guid("4D1E55B2-F16F-11CF-88CB-001111000030"); @@ -138,6 +139,15 @@ namespace OpenTK.Platform.Windows keyboard_driver = new WinRawKeyboard(Parent.Handle); mouse_driver = new WinRawMouse(Parent.Handle); joystick_driver = new WinMMJoystick(); + try + { + gamepad_driver = new XInputJoystick(); + } + catch (Exception e) + { + Debug.Print("[Win] XInput driver not supported, falling back to WinMM"); + gamepad_driver = new MappedGamePadDriver(); + } DevNotifyHandle = RegisterForDeviceNotifications(Parent); } @@ -187,12 +197,12 @@ namespace OpenTK.Platform.Windows public override IGamePadDriver GamePadDriver { - get { return joystick_driver; } + get { return gamepad_driver; } } public override IJoystickDriver2 JoystickDriver { - get { throw new NotImplementedException(); } + get { return joystick_driver; } } #endregion From 7bab950cc025c5a7afbeae2bbc3c99312c76b15f Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 15:01:10 +0100 Subject: [PATCH 064/154] Implemented structural equality --- Source/OpenTK/Input/JoystickCapabilities.cs | 39 ++++++++++- Source/OpenTK/Input/JoystickState.cs | 73 ++++++++++++++++++--- 2 files changed, 101 insertions(+), 11 deletions(-) diff --git a/Source/OpenTK/Input/JoystickCapabilities.cs b/Source/OpenTK/Input/JoystickCapabilities.cs index b25fa69b..80036211 100644 --- a/Source/OpenTK/Input/JoystickCapabilities.cs +++ b/Source/OpenTK/Input/JoystickCapabilities.cs @@ -33,7 +33,7 @@ using System.Text; namespace OpenTK.Input { - public struct JoystickCapabilities + public struct JoystickCapabilities : IEquatable { byte axis_count; byte button_count; @@ -69,6 +69,33 @@ namespace OpenTK.Input get { return button_count; } } + public bool IsConnected + { + get { return is_connected; } + } + + public override string ToString() + { + return String.Format( + "{{Axes: {0}; Buttons: {1}; IsConnected: {2}}}", + AxisCount, ButtonCount, IsConnected); + } + + public override int GetHashCode() + { + return + AxisCount.GetHashCode() ^ + ButtonCount.GetHashCode() ^ + IsConnected.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is JoystickCapabilities && + Equals((JoystickCapabilities)obj); + } + #endregion #region Private Members @@ -80,10 +107,16 @@ namespace OpenTK.Input #endregion - public bool IsConnected + #region IEquatable Members + + public bool Equals(JoystickCapabilities other) { - get { return is_connected; } + return + AxisCount == other.AxisCount && + ButtonCount == other.ButtonCount && + IsConnected == other.IsConnected; } + #endregion } } diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index 8a233df6..1b2a1299 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -34,7 +34,7 @@ using System.Text; namespace OpenTK.Input { - public struct JoystickState + public struct JoystickState : IEquatable { // If we ever add more values to JoystickAxis or JoystickButton // then we'll need to increase these limits. @@ -59,13 +59,7 @@ namespace OpenTK.Input float value = 0.0f; if (axis >= 0 && axis < MaxAxes) { - unsafe - { - fixed (short* paxis = axes) - { - value = *(paxis + axis) * ConversionFactor; - } - } + value = GetAxisUnsafe(axis) * ConversionFactor; } else { @@ -94,6 +88,38 @@ namespace OpenTK.Input get { return is_connected; } } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < MaxAxes; i++) + { + sb.Append(" "); + sb.Append(GetAxis(i)); + } + return String.Format( + "{{Axes:{0}; Buttons: {1}; IsConnected: {2}}}", + sb.ToString(), + Convert.ToString((int)buttons, 2), + IsConnected); + } + + public override int GetHashCode() + { + int hash = buttons.GetHashCode() ^ IsConnected.GetHashCode(); + for (int i = 0; i < MaxAxes; i++) + { + hash ^= GetAxisUnsafe(i).GetHashCode(); + } + return hash; + } + + public override bool Equals(object obj) + { + return + obj is JoystickState && + Equals((JoystickState)obj); + } + #endregion #region Internal Members @@ -132,5 +158,36 @@ namespace OpenTK.Input } #endregion + + #region Private Members + + short GetAxisUnsafe(int index) + { + unsafe + { + fixed (short* paxis = axes) + { + return *(paxis + index); + } + } + } + + #endregion + + #region IEquatable Members + + public bool Equals(JoystickState other) + { + bool equals = + buttons == other.buttons && + IsConnected == other.IsConnected; + for (int i = 0; equals && i < MaxAxes; i++) + { + equals &= GetAxisUnsafe(i) == other.GetAxisUnsafe(i); + } + return equals; + } + + #endregion } } From 97b8710339fb4c48f74e5caa0fee0a410e4cfa5e Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 15:01:33 +0100 Subject: [PATCH 065/154] Added state output for OpenTK.Input.Joystick --- .../Examples/OpenTK/Test/GameWindowStates.cs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 8359a552..aa9d27d2 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -228,14 +228,31 @@ namespace Examples.Tests int DrawGamePads(Graphics gfx, int line) { + line++; DrawString(gfx, "GamePads:", line++); for (int i = 0; i < 4; i++) { GamePadCapabilities caps = GamePad.GetCapabilities(i); GamePadState state = GamePad.GetState(i); - DrawString(gfx, caps.ToString(), line++); - DrawString(gfx, state.ToString(), line++); + if (state.IsConnected) + { + DrawString(gfx, caps.ToString(), line++); + DrawString(gfx, state.ToString(), line++); + } } + line++; + DrawString(gfx, "Joysticks:", line++); + for (int i = 0; i < 4; i++) + { + JoystickCapabilities caps = Joystick.GetCapabilities(i); + JoystickState state = Joystick.GetState(i); + if (state.IsConnected) + { + DrawString(gfx, caps.ToString(), line++); + DrawString(gfx, state.ToString(), line++); + } + } + return line; } From 3c1404f0ac04faaae0ed64d220be1ea783478b9a Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 15:51:25 +0100 Subject: [PATCH 066/154] Improved WinMMJoystickDriver hotplugging behavior --- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 882ce5f0..9f84c09e 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -133,6 +133,16 @@ namespace OpenTK.Platform.Windows return stick; } + void UnplugJoystick(int index) + { + // Reset the system configuration. Without this, + // joysticks that are reconnected on different + // ports are given different ids, making it + // impossible to reconnect a disconnected user. + UnsafeNativeMethods.joyConfigChanged(0); + Debug.Print("[Win] WinMM joystick {0} unplugged", index); + } + bool IsValid(int index) { return index >= 0 && index < UnsafeNativeMethods.joyGetNumDevs(); @@ -258,6 +268,10 @@ namespace OpenTK.Platform.Windows // gpcaps.DPadCount++; return caps; } + else if (result == JoystickError.Unplugged) + { + UnplugJoystick(index); + } } else { @@ -276,18 +290,32 @@ namespace OpenTK.Platform.Windows JoyInfoEx info = new JoyInfoEx(); info.Size = JoyInfoEx.SizeInBytes; info.Flags = JoystickFlags.All; - UnsafeNativeMethods.joyGetPosEx(index, ref info); - state.SetAxis(JoystickAxis.Axis0, (short)info.XPos); - state.SetAxis(JoystickAxis.Axis1, (short)info.YPos); - state.SetAxis(JoystickAxis.Axis2, (short)info.ZPos); - state.SetAxis(JoystickAxis.Axis3, (short)info.RPos); - state.SetAxis(JoystickAxis.Axis4, (short)info.ZPos); - state.SetAxis(JoystickAxis.Axis5, (short)info.RPos); - - for (int i = 0; i < 16; i++) + JoystickError result = UnsafeNativeMethods.joyGetPosEx(index, ref info); + if (result == JoystickError.NoError) { - state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); + state.SetAxis(JoystickAxis.Axis0, (short)info.XPos); + state.SetAxis(JoystickAxis.Axis1, (short)info.YPos); + state.SetAxis(JoystickAxis.Axis2, (short)info.ZPos); + state.SetAxis(JoystickAxis.Axis3, (short)info.RPos); + state.SetAxis(JoystickAxis.Axis4, (short)info.ZPos); + state.SetAxis(JoystickAxis.Axis5, (short)info.RPos); + + for (int i = 0; i < 16; i++) + { + state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); + } + + state.SetIsConnected(true); + } + else if (result == JoystickError.Unplugged) + { + UnplugJoystick(index); + } + else + { + // Joystick not existent or other error. No need to spam the log + //Debug.Print("[Win] WinMM joyGetPosEx failed. Error: {0}", result); } } else @@ -441,9 +469,11 @@ namespace OpenTK.Platform.Windows [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity] public static extern JoystickError joyGetDevCaps(int uJoyID, out JoyCaps pjc, int cbjc); [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity] - public static extern uint joyGetPosEx(int uJoyID, ref JoyInfoEx pji); + public static extern JoystickError joyGetPosEx(int uJoyID, ref JoyInfoEx pji); [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity] public static extern int joyGetNumDevs(); + [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity] + public static extern JoystickError joyConfigChanged(int flags); } #endregion From 3c6298a1e6102cd6a54418c8cfc48a135b0721ce Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 16:42:48 +0100 Subject: [PATCH 067/154] Fixed WinMM offsets for IJoystickDevice2 --- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 9f84c09e..fa84aba1 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -148,6 +148,12 @@ namespace OpenTK.Platform.Windows return index >= 0 && index < UnsafeNativeMethods.joyGetNumDevs(); } + static short CalculateOffset(int pos, int min, int max) + { + int offset = (ushort.MaxValue * (pos - min)) / (max - min) - short.MaxValue; + return (short)offset; + } + #endregion #region IJoystickDriver @@ -294,29 +300,30 @@ namespace OpenTK.Platform.Windows JoystickError result = UnsafeNativeMethods.joyGetPosEx(index, ref info); if (result == JoystickError.NoError) { - state.SetAxis(JoystickAxis.Axis0, (short)info.XPos); - state.SetAxis(JoystickAxis.Axis1, (short)info.YPos); - state.SetAxis(JoystickAxis.Axis2, (short)info.ZPos); - state.SetAxis(JoystickAxis.Axis3, (short)info.RPos); - state.SetAxis(JoystickAxis.Axis4, (short)info.ZPos); - state.SetAxis(JoystickAxis.Axis5, (short)info.RPos); - - for (int i = 0; i < 16; i++) + JoyCaps caps; + result = UnsafeNativeMethods.joyGetDevCaps(index, out caps, JoyCaps.SizeInBytes); + if (result == JoystickError.NoError) { - state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); - } + state.SetAxis(JoystickAxis.Axis0, CalculateOffset(info.XPos, caps.XMin, caps.XMax)); + state.SetAxis(JoystickAxis.Axis1, CalculateOffset(info.YPos, caps.YMin, caps.YMax)); + state.SetAxis(JoystickAxis.Axis2, CalculateOffset(info.ZPos, caps.ZMin, caps.ZMax)); + state.SetAxis(JoystickAxis.Axis3, CalculateOffset(info.RPos, caps.RMin, caps.RMax)); + state.SetAxis(JoystickAxis.Axis4, CalculateOffset(info.UPos, caps.UMin, caps.UMax)); + state.SetAxis(JoystickAxis.Axis5, CalculateOffset(info.VPos, caps.VMin, caps.VMax)); - state.SetIsConnected(true); + for (int i = 0; i < 16; i++) + { + state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); + } + + state.SetIsConnected(true); + } } - else if (result == JoystickError.Unplugged) + + if (result == JoystickError.Unplugged) { UnplugJoystick(index); } - else - { - // Joystick not existent or other error. No need to spam the log - //Debug.Print("[Win] WinMM joyGetPosEx failed. Error: {0}", result); - } } else { From 0a71bbe065b0dd7cf1e71cc25f7dd19dc9881b4d Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 24 Dec 2013 17:06:39 +0100 Subject: [PATCH 068/154] Improved ToString implementation --- Source/OpenTK/Input/GamePadButtons.cs | 14 +------------- Source/OpenTK/Input/GamePadThumbSticks.cs | 4 ++-- Source/OpenTK/Input/GamePadTriggers.cs | 2 +- Source/OpenTK/Input/Joystick.cs | 5 +++++ Source/OpenTK/Input/JoystickState.cs | 6 +++--- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index aeb97b59..c13a9f0c 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -109,19 +109,7 @@ namespace OpenTK.Input public override string ToString() { - return String.Format( - "{{{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}}}", - A == ButtonState.Pressed ? "A" : String.Empty, - B == ButtonState.Pressed ? "B" : String.Empty, - X == ButtonState.Pressed ? "X" : String.Empty, - Y == ButtonState.Pressed ? "Y" : String.Empty, - LeftShoulder == ButtonState.Pressed ? "L" : String.Empty, - RightShoulder == ButtonState.Pressed ? "R" : String.Empty, - Back == ButtonState.Pressed ? " Back" : String.Empty, - Start == ButtonState.Pressed ? " Start" : String.Empty, - BigButton == ButtonState.Pressed ? " Big" : String.Empty, - LeftStick == ButtonState.Pressed ? " LStick" : String.Empty, - RightStick == ButtonState.Pressed ? " RStick" : String.Empty); + return Convert.ToString((int)buttons, 2).PadLeft(10, '0'); } public override int GetHashCode() diff --git a/Source/OpenTK/Input/GamePadThumbSticks.cs b/Source/OpenTK/Input/GamePadThumbSticks.cs index 59eb4ee3..63838c6f 100644 --- a/Source/OpenTK/Input/GamePadThumbSticks.cs +++ b/Source/OpenTK/Input/GamePadThumbSticks.cs @@ -73,8 +73,8 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Left: {0}; Right: {1}}}", - Left, Right); + "{{Left: ({0:f4}; {1:f4}); Right: ({2:f4}; {3:f4})}}", + Left.X, Left.Y, Right.X, Right.Y); } public override int GetHashCode() diff --git a/Source/OpenTK/Input/GamePadTriggers.cs b/Source/OpenTK/Input/GamePadTriggers.cs index ecff49c7..0e505d81 100644 --- a/Source/OpenTK/Input/GamePadTriggers.cs +++ b/Source/OpenTK/Input/GamePadTriggers.cs @@ -69,7 +69,7 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Left: {0}; Right: {1}}}", + "{{Left: {0:f2}; Right: {1:f2}}}", Left, Right); } diff --git a/Source/OpenTK/Input/Joystick.cs b/Source/OpenTK/Input/Joystick.cs index 0458abed..378b11f4 100644 --- a/Source/OpenTK/Input/Joystick.cs +++ b/Source/OpenTK/Input/Joystick.cs @@ -47,5 +47,10 @@ namespace OpenTK.Input { return implementation.GetState(index); } + + //public string GetName(int index) + //{ + // return implementation.GetName(index); + //} } } diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index 1b2a1299..e14ac2d2 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -41,7 +41,7 @@ namespace OpenTK.Input internal const int MaxAxes = 10; internal const int MaxButtons = 32; - const float ConversionFactor = 1.0f / (short.MaxValue + 1); + const float ConversionFactor = 1.0f / (short.MaxValue + 0.5f); unsafe fixed short axes[MaxAxes]; int buttons; @@ -94,12 +94,12 @@ namespace OpenTK.Input for (int i = 0; i < MaxAxes; i++) { sb.Append(" "); - sb.Append(GetAxis(i)); + sb.Append(String.Format("{0:f4}", GetAxis(i))); } return String.Format( "{{Axes:{0}; Buttons: {1}; IsConnected: {2}}}", sb.ToString(), - Convert.ToString((int)buttons, 2), + Convert.ToString((int)buttons, 2).PadLeft(16, '0'), IsConnected); } From bd1fb1883629c370ee3c4de70020bda858423aec Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 24 Dec 2013 17:16:16 +0100 Subject: [PATCH 069/154] Use IGamePadDriver through MappedGamePadDriver --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 30 +++++------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index 613d1c64..0967afef 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -50,7 +50,7 @@ namespace OpenTK.Platform.MacOS // Requires Mac OS X 10.5 or higher. // Todo: create a driver for older installations. Maybe use CGGetLastMouseDelta for that? - class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IGamePadDriver, IJoystickDriver2 + class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IJoystickDriver2 { #region Fields @@ -69,6 +69,8 @@ namespace OpenTK.Platform.MacOS readonly CFString InputLoopMode = CF.RunLoopModeDefault; readonly CFDictionary DeviceTypes = new CFDictionary(); + readonly MappedGamePadDriver mapped_gamepad = new MappedGamePadDriver(); + NativeMethods.IOHIDDeviceCallback HandleDeviceAdded; NativeMethods.IOHIDDeviceCallback HandleDeviceRemoved; NativeMethods.IOHIDValueCallback HandleDeviceValueReceived; @@ -291,10 +293,9 @@ namespace OpenTK.Platform.MacOS public IMouseDriver2 MouseDriver { get { return this; } } public IKeyboardDriver2 KeyboardDriver { get { return this; } } - public IGamePadDriver GamePadDriver { get { return this; } } + public IGamePadDriver GamePadDriver { get { return mapped_gamepad; } } public IJoystickDriver2 JoystickDriver { get { return this; } } - #endregion #region IMouseDriver2 Members @@ -368,35 +369,16 @@ namespace OpenTK.Platform.MacOS #endregion - #region IGamePadDriver Members - - public GamePadState GetState(int index) - { - return new GamePadState(); - } - - public GamePadCapabilities GetCapabilities(int index) - { - return new GamePadCapabilities(); - } - - public string GetName(int index) - { - throw new NotImplementedException(); - } - - #endregion - #region IJoystickDriver2 Members JoystickState IJoystickDriver2.GetState(int index) { - throw new NotImplementedException(); + return new JoystickState(); } JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) { - throw new NotImplementedException(); + return new JoystickCapabilities(); } #endregion From 022e5c845c07d3e6ac198f970068243dfaf48c6a Mon Sep 17 00:00:00 2001 From: thefiddler Date: Wed, 18 Dec 2013 15:50:59 +0100 Subject: [PATCH 070/154] Implemented SDL2 Joystick and GameController events --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 152 +++++++++++++++++++++++++--- 1 file changed, 138 insertions(+), 14 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 9bf07558..60e72876 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -500,6 +500,53 @@ namespace OpenTK.Platform.SDL2 LASTEVENT = 0xFFFF } + enum GameControllerAxis : byte + { + Invalid = 0xff, + LeftX = 0, + LeftY, + RightX, + RightY, + TriggerLeft, + TriggerRight, + Max + } + + enum GameControllerButton : byte + { + INVALID = 0xff, + A = 0, + B, + X, + Y, + BACK, + GUIDE, + START, + LEFTSTICK, + RIGHTSTICK, + LEFTSHOULDER, + RIGHTSHOULDER, + DPAD_UP, + DPAD_DOWN, + DPAD_LEFT, + DPAD_RIGHT, + Max + } + + [Flags] + enum HatPosition : byte + { + Centered = 0x00, + Up = 0x01, + Right = 0x02, + Down = 0x03, + Left = 0x04, + RightUp = Right | Up, + RightDown = Right | Down, + LeftUp = Left | Up, + LeftDown = Left | Down + } + enum Keycode { UNKNOWN = 0, @@ -1079,6 +1126,41 @@ namespace OpenTK.Platform.SDL2 #region Structs + struct ControllerAxisEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public GameControllerAxis Axis; + byte padding1; + byte padding2; + byte padding3; + public short Value; + ushort padding4; + } + + struct ControllerButtonEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public GameControllerButton Button; + public State State; + byte padding1; + byte padding2; + } + + struct ControllerDeviceEvent + { + public EventType Type; + public uint Timestamp; + + /// + /// The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event + /// + public int Which; + } + struct DisplayMode { public uint Format; @@ -1109,21 +1191,21 @@ namespace OpenTK.Platform.SDL2 public MouseWheelEvent Wheel; [FieldOffset(0)] public JoyAxisEvent JoyAxis; + [FieldOffset(0)] + public JoyBallEvent JoyBall; + [FieldOffset(0)] + public JoyHatEvent JoyHat; + [FieldOffset(0)] + public JoyButtonEvent JoyButton; + [FieldOffset(0)] + public JoyDeviceEvent JoyDevice; + [FieldOffset(0)] + public ControllerAxisEvent ControllerAxis; + [FieldOffset(0)] + public ControllerButtonEvent ControllerButton; + [FieldOffset(0)] + public ControllerDeviceEvent ControllerDevice; #if false - [FieldOffset(0)] - public JoyBallEvent jball; - [FieldOffset(0)] - public JoyHatEvent jhat; - [FieldOffset(0)] - public JoyButtonEvent jbutton; - [FieldOffset(0)] - public JoyDeviceEvent jdevice; - [FieldOffset(0)] - public ControllerAxisEvent caxis; - [FieldOffset(0)] - public ControllerButtonEvent cbutton; - [FieldOffset(0)] - public ControllerDeviceEvent cdevice; [FieldOffset(0)] public QuitEvent quit; [FieldOffset(0)] @@ -1154,6 +1236,48 @@ namespace OpenTK.Platform.SDL2 UInt16 padding4; } + struct JoyBallEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public byte Ball; + byte padding1; + byte padding2; + byte padding3; + public short Xrel; + public short Yrel; + } + + struct JoyButtonEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public byte Button; + public State State; + byte padding1; + byte padding2; + } + + struct JoyDeviceEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + } + + struct JoyHatEvent + { + public EventType Type; + public uint Timestamp; + public int Which; + public byte Hat; + public HatPosition Value; + byte padding1; + byte padding2; + } + struct KeyboardEvent { public EventType Type; From d9985fc5714e8ba74a72d39bac90aedc7cf66926 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Wed, 18 Dec 2013 17:16:29 +0100 Subject: [PATCH 071/154] Use SDL2 event API for joystick devices --- .../OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 38 +++- .../Platform/SDL2/Sdl2JoystickDriver.cs | 211 ++++++++++++++---- 2 files changed, 204 insertions(+), 45 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index 7a571b14..de174875 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -92,6 +92,42 @@ namespace OpenTK.Platform.SDL2 case EventType.MOUSEWHEEL: driver.mouse_driver.ProcessWheelEvent(ev.Wheel); break; + + case EventType.JOYDEVICEADDED: + case EventType.JOYDEVICEREMOVED: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyDevice); + break; + + case EventType.JOYAXISMOTION: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyAxis); + break; + + case EventType.JOYBALLMOTION: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyBall); + break; + + case EventType.JOYBUTTONDOWN: + case EventType.JOYBUTTONUP: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyButton); + break; + + case EventType.JOYHATMOTION: + driver.joystick_driver.ProcessJoystickEvent(ev.JoyHat); + break; + + case EventType.CONTROLLERDEVICEADDED: + case EventType.CONTROLLERDEVICEREMOVED: + driver.joystick_driver.ProcessControllerEvent(ev.ControllerDevice); + break; + + case EventType.CONTROLLERAXISMOTION: + driver.joystick_driver.ProcessControllerEvent(ev.ControllerAxis); + break; + + case EventType.CONTROLLERBUTTONDOWN: + case EventType.CONTROLLERBUTTONUP: + driver.joystick_driver.ProcessControllerEvent(ev.ControllerButton); + break; } } } @@ -172,7 +208,7 @@ namespace OpenTK.Platform.SDL2 { get { - throw new NotImplementedException(); + return joystick_driver; } } diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 729cee13..380bbd67 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -40,6 +40,7 @@ namespace OpenTK.Platform.SDL2 public float RangeMultiplier { get { return 1.0f / 32768.0f; } } public int HatCount { get; set; } public int BallCount { get; set; } + public bool IsConnected { get; set; } } readonly List joysticks = new List(); @@ -49,42 +50,181 @@ namespace OpenTK.Platform.SDL2 public Sdl2JoystickDriver() { joysticks_readonly = joysticks.AsReadOnly(); - - RefreshJoysticks(); - } #region Private Members - void RefreshJoysticks() + JoystickDevice OpenJoystick(int id) { - joysticks.Clear(); + JoystickDevice joystick = null; + int num_axes = 0; + int num_buttons = 0; + int num_hats = 0; + int num_balls = 0; - int count = SDL.NumJoysticks(); - for (int i = 0; i < count; i++) + IntPtr handle = SDL.JoystickOpen(id); + if (handle != IntPtr.Zero) { - JoystickDevice joystick = null; - int num_axes = 0; - int num_buttons = 0; - int num_hats = 0; - int num_balls = 0; + num_axes = SDL.JoystickNumAxes(handle); + num_buttons = SDL.JoystickNumButtons(handle); + num_hats = SDL.JoystickNumHats(handle); + num_balls = SDL.JoystickNumBalls(handle); - IntPtr handle = SDL.JoystickOpen(i); - if (handle != IntPtr.Zero) - { - num_axes = SDL.JoystickNumAxes(handle); - num_buttons = SDL.JoystickNumButtons(handle); - num_hats = SDL.JoystickNumHats(handle); - num_balls = SDL.JoystickNumBalls(handle); + joystick = new JoystickDevice(id, num_axes, num_buttons); + joystick.Description = SDL.JoystickName(handle); + joystick.Details.Handle = handle; + joystick.Details.HatCount = num_hats; + joystick.Details.BallCount = num_balls; - joystick = new JoystickDevice(i, num_axes, num_buttons); - joystick.Description = SDL.JoystickName(handle); - joystick.Details.Handle = handle; - joystick.Details.HatCount = num_hats; - joystick.Details.BallCount = num_balls; - joysticks.Add(joystick); - } + Debug.Print("[SDL2] Joystick device {0} opened successfully. ", id); + Debug.Print("\t\t'{0}' has {1} axes, {2} buttons, {3} hats, {4} balls", + joystick.Description, joystick.Axis.Count, joystick.Button.Count, + joystick.Details.HatCount, joystick.Details.BallCount); } + else + { + Debug.Print("[SDL2] Failed to open joystick device {0}", id); + } + + return joystick; + } + + bool IsJoystickValid(int id) + { + return id >= 0 && id < joysticks.Count; + } + + #endregion + + #region Public Members + + public void ProcessJoystickEvent(JoyDeviceEvent ev) + { + int id = ev.Which; + if (id < 0) + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + return; + } + + switch (ev.Type) + { + case EventType.JOYDEVICEADDED: + { + // Make sure we have enough space to store this instance + if (joysticks.Count <= id) + { + joysticks.Capacity = OpenTK.MathHelper.NextPowerOfTwo(id); + } + + IntPtr handle = SDL.JoystickOpen(id); + if (handle != IntPtr.Zero) + { + JoystickDevice joystick = OpenJoystick(id); + if (joysticks != null) + { + joystick.Details.IsConnected = true; + joysticks[id] = joystick; + } + } + } + break; + + case EventType.JOYDEVICEREMOVED: + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + joystick.Details.IsConnected = false; + } + break; + } + } + + public void ProcessJoystickEvent(JoyAxisEvent ev) + { + int id = ev.Which; + if (IsJoystickValid(id)) + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + float value = ev.Value * joystick.Details.RangeMultiplier; + joystick.SetAxis((JoystickAxis)ev.Axis, value); + } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } + } + + public void ProcessJoystickEvent(JoyBallEvent ev) + { + int id = ev.Which; + if (IsJoystickValid(id)) + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + // Todo: does it make sense to support balls? + } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } + } + + public void ProcessJoystickEvent(JoyButtonEvent ev) + { + int id = ev.Which; + if (IsJoystickValid(id)) + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + joystick.SetButton((JoystickButton)ev.Button, ev.State == State.Pressed); + } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } + } + + public void ProcessJoystickEvent(JoyHatEvent ev) + { + int id = ev.Which; + if (IsJoystickValid(id)) + { + JoystickDevice joystick = (JoystickDevice)joysticks[id]; + // Todo: map hat to an extra axis + } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } + } + + public void ProcessControllerEvent(ControllerDeviceEvent ev) + { + int id = ev.Which; + + switch (ev.Type) + { + case EventType.CONTROLLERDEVICEADDED: + break; + + case EventType.CONTROLLERDEVICEREMOVED: + break; + + case EventType.CONTROLLERDEVICEREMAPPED: + break; + } + } + + public void ProcessControllerEvent(ControllerAxisEvent ev) + { + int id = ev.Which; + + + } + + public void ProcessControllerEvent(ControllerButtonEvent ev) + { + int id = ev.Which; + + } #endregion @@ -101,24 +241,7 @@ namespace OpenTK.Platform.SDL2 public void Poll() { - SDL.JoystickUpdate(); - foreach (var j in joysticks) - { - var joystick = (JoystickDevice)j; - IntPtr handle = joystick.Details.Handle; - - for (int i = 0; i < joystick.Axis.Count; i++) - { - var axis = JoystickAxis.Axis0 + i; - joystick.SetAxis(axis, SDL.JoystickGetAxis(handle, i) * joystick.Details.RangeMultiplier); - } - - for (int i = 0; i < joystick.Button.Count; i++) - { - var button = JoystickButton.Button0 + i; - joystick.SetButton(button, SDL.JoystickGetButton(handle, i) != 0); - } - } + // Do nothing } #endregion From ee65f81f5614e13ad98da982e3863156694eefbe Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 19 Dec 2013 10:42:12 +0100 Subject: [PATCH 072/154] Implemented GameController API bindings --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 54 +++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 60e72876..2232e686 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -23,8 +23,6 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // -using System.Runtime.InteropServices; - #endregion @@ -118,6 +116,49 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_FreeSurface", ExactSpelling = true)] public static extern void FreeSurface(IntPtr surface); + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerName", ExactSpelling = true)] + static extern IntPtr GameControllerNameInternal(IntPtr gamecontroller); + + /// + /// Return the name for an openend game controller instance. + /// + /// The name of the game controller name. + /// Pointer to a game controller instance returned by GameControllerOpen. + public static string GameControllerName(IntPtr gamecontroller) + { + unsafe + { + return new string((sbyte*)GameControllerNameInternal(gamecontroller)); + } + } + + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetAxis", ExactSpelling = true)] + public static extern short GameControllerGetAxis(IntPtr gamecontroller, GameControllerAxis axis); + + /// > + /// Gets the current state of a button on a game controller. + /// + /// A game controller handle previously opened with GameControllerOpen. + /// A zero-based GameControllerButton value. + /// true if the specified button is pressed; false otherwise. + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetButton", ExactSpelling = true)] + public static extern bool GameControllerGetButton(IntPtr gamecontroller, GameControllerButton button); + + /// + /// Opens a game controller for use. + /// + /// + /// A zero-based index for the game controller. + /// This index is the value which will identify this controller in future controller events. + /// + /// A handle to the game controller instance, or IntPtr.Zero in case of error. + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerOpen", ExactSpelling = true)] + public static extern IntPtr GameControllerOpen(int joystick_index); + [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetCurrentDisplayMode", ExactSpelling = true)] public static extern int GetCurrentDisplayMode(int displayIndex, out DisplayMode mode); @@ -192,6 +233,15 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_Init", ExactSpelling = true)] public static extern int Init(SystemFlags flags); + /// + /// Determines if the specified joystick is supported by the GameController API. + /// + /// true if joystick_index is supported by the GameController API; false otherwise. + /// The index of the joystick to check. + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_IsGameController", ExactSpelling = true)] + public static extern bool IsGameController(int joystick_index); + [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickClose", ExactSpelling = true)] public static extern void JoystickClose(IntPtr joystick); From 484af186738856b689afbecd76840c2f6c355c0f Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 19 Dec 2013 16:27:26 +0100 Subject: [PATCH 073/154] Updated internal IGamePadDriver interface --- Source/OpenTK/Input/IGamePadDriver.cs | 14 +--- .../Platform/SDL2/Sdl2JoystickDriver.cs | 66 ++++++++++++++++--- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 9 ++- Source/OpenTK/Platform/X11/X11Joystick.cs | 10 +-- 4 files changed, 71 insertions(+), 28 deletions(-) diff --git a/Source/OpenTK/Input/IGamePadDriver.cs b/Source/OpenTK/Input/IGamePadDriver.cs index 718d1bc1..fc24c8f8 100644 --- a/Source/OpenTK/Input/IGamePadDriver.cs +++ b/Source/OpenTK/Input/IGamePadDriver.cs @@ -6,19 +6,11 @@ namespace OpenTK.Input { interface IGamePadDriver { - /// - /// Retrieves the combined for all gamepad devices. - /// - /// A structure containing the combined state for all gamepad devices. - GamePadState GetState(); - /// - /// Retrieves the for the specified gamepad device. - /// - /// The index of the keyboard device. - /// A structure containing the state of the gamepad device. GamePadState GetState(int index); + GamePadCapabilities GetCapabilities(int index); + /// /// Retrieves the device name for the gamepad device. /// @@ -26,6 +18,6 @@ namespace OpenTK.Input /// A with the name of the specified device or . /// /// If no device exists at the specified index, the return value is . - string GetDeviceName(int index); + string GetName(int index); } } diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 380bbd67..2af3f977 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -34,18 +34,32 @@ namespace OpenTK.Platform.SDL2 { class Sdl2JoystickDriver : IJoystickDriver, IGamePadDriver, IDisposable { + const float RangeMultiplier = 1.0f / 32768.0f; + struct Sdl2JoystickDetails { public IntPtr Handle { get; set; } - public float RangeMultiplier { get { return 1.0f / 32768.0f; } } public int HatCount { get; set; } public int BallCount { get; set; } public bool IsConnected { get; set; } } + class Sdl2GamePad + { + public IntPtr Handle { get; private set; } + public GamePadState State { get; set; } + + public Sdl2GamePad(IntPtr handle) + { + Handle = handle; + } + } + readonly List joysticks = new List(); + readonly Dictionary controllers = new Dictionary(); + IList joysticks_readonly; - bool disposed = false; + bool disposed; public Sdl2JoystickDriver() { @@ -94,6 +108,11 @@ namespace OpenTK.Platform.SDL2 return id >= 0 && id < joysticks.Count; } + bool IsControllerValid(int id) + { + return controllers.ContainsKey(id); + } + #endregion #region Public Members @@ -145,7 +164,7 @@ namespace OpenTK.Platform.SDL2 if (IsJoystickValid(id)) { JoystickDevice joystick = (JoystickDevice)joysticks[id]; - float value = ev.Value * joystick.Details.RangeMultiplier; + float value = ev.Value * RangeMultiplier; joystick.SetAxis((JoystickAxis)ev.Axis, value); } else @@ -203,12 +222,27 @@ namespace OpenTK.Platform.SDL2 switch (ev.Type) { case EventType.CONTROLLERDEVICEADDED: + if (SDL.IsGameController(id)) + { + IntPtr handle = SDL.GameControllerOpen(id); + if (handle != IntPtr.Zero) + { + Sdl2GamePad pad = new Sdl2GamePad(handle); + pad.State.SetConnected(true); + controllers.Add(id, pad); + } + } break; case EventType.CONTROLLERDEVICEREMOVED: + if (IsControllerValid(id)) + { + controllers[id].State.SetConnected(false); + } break; case EventType.CONTROLLERDEVICEREMAPPED: + // Todo: what should we do in this case? break; } } @@ -216,15 +250,27 @@ namespace OpenTK.Platform.SDL2 public void ProcessControllerEvent(ControllerAxisEvent ev) { int id = ev.Which; - - + if (IsControllerValid(id)) + { + controllers[id].State.SetAxis((GamePadAxis)ev.Axis, ev.Value); + } + else + { + Debug.Print("[SDL2] Invalid game controller handle {0} in {1}", id, ev.Type); + } } public void ProcessControllerEvent(ControllerButtonEvent ev) { int id = ev.Which; - - + if (IsControllerValid(id)) + { + controllers[id].State.SetButton((Buttons)ev.Button, ev.State == State.Pressed); + } + else + { + Debug.Print("[SDL2] Invalid game controller handle {0} in {1}", id, ev.Type); + } } #endregion @@ -248,9 +294,9 @@ namespace OpenTK.Platform.SDL2 #region IGamePadDriver Members - public GamePadState GetState() + public GamePadCapabilities GetCapabilities(int index) { - return new GamePadState(); + return new GamePadCapabilities(); } public GamePadState GetState(int index) @@ -263,7 +309,7 @@ namespace OpenTK.Platform.SDL2 return new GamePadState(); } - public string GetDeviceName(int index) + public string GetName(int index) { return String.Empty; } diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 32a00c7a..ca229700 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -428,8 +428,9 @@ namespace OpenTK.Platform.Windows #endregion - //HACK implement - public GamePadState GetState() + #region IGamePadDriver Members + + public GamePadCapabilities GetCapabilities(int index) { throw new NotImplementedException(); } @@ -439,9 +440,11 @@ namespace OpenTK.Platform.Windows throw new NotImplementedException(); } - public string GetDeviceName(int index) + public string GetName(int index) { throw new NotImplementedException(); } + + #endregion } } diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs index 85299eb1..b4948169 100644 --- a/Source/OpenTK/Platform/X11/X11Joystick.cs +++ b/Source/OpenTK/Platform/X11/X11Joystick.cs @@ -259,21 +259,23 @@ namespace OpenTK.Platform.X11 #endregion - //HACK implement - public GamePadState GetState() + #region IGamePadDriver Members + + public GamePadCapabilities GetCapabilities(int index) { throw new NotImplementedException(); } public GamePadState GetState(int index) { - Poll(); throw new NotImplementedException(); } - public string GetDeviceName(int index) + public string GetName(int index) { throw new NotImplementedException(); } + + #endregion } } From ecd04a3cad181552f59d57c1cd1ccd48b2e95529 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 19 Dec 2013 16:27:57 +0100 Subject: [PATCH 074/154] Implemented GamePadButtons --- Source/OpenTK/Input/Buttons.cs | 213 ++++++++++++++++++++++++++ Source/OpenTK/Input/GamePadButton.cs | 68 -------- Source/OpenTK/Input/GamePadButtons.cs | 131 ++++++++++++++++ 3 files changed, 344 insertions(+), 68 deletions(-) create mode 100644 Source/OpenTK/Input/Buttons.cs delete mode 100644 Source/OpenTK/Input/GamePadButton.cs create mode 100644 Source/OpenTK/Input/GamePadButtons.cs diff --git a/Source/OpenTK/Input/Buttons.cs b/Source/OpenTK/Input/Buttons.cs new file mode 100644 index 00000000..739a8fcd --- /dev/null +++ b/Source/OpenTK/Input/Buttons.cs @@ -0,0 +1,213 @@ +// +// GamePadButton.cs +// +// Author: +// robert <${AuthorEmail}> +// +// Copyright (c) 2012 robert +// +// 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. +using System; + +namespace OpenTK.Input +{ + public enum Buttons + { + /// + /// DPad up direction button + /// + DPadUp = 1 << 0, + + /// + /// DPad down direction button + /// + DPadDown = 1 << 1, + + /// + /// DPad left direction button + /// + DPadLeft = 1 << 2, + + /// + /// DPad right direction button + /// + DPadRight = 1 << 3, + + /// + /// Start button + /// + Start = 1 << 4, + + /// + /// Back button + /// + Back = 1 << 5, + + /// + /// Left stick button + /// + LeftStick = 1 << 6, + + /// + /// Right stick button + /// + RightStick = 1 << 7, + + /// + /// Left shoulder button + /// + LeftShoulder = 1 << 8, + + /// + /// Right shoulder button + /// + RightShoulder = 1 << 9, + + /// + /// Home button + /// + Home = 1 << 11, + + /// + /// Home button + /// + BigButton = Home, + + /// + /// A button + /// + A = 1 << 12, + + /// + /// B button + /// + B = 1 << 13, + + /// + /// X button + /// + X = 1 << 14, + + /// + /// Y button + /// + Y = 1 << 15, + + /// + /// Left thumbstick left direction button + /// + LeftThumbstickLeft = 1 << 21, + + /// + /// Right trigger button + /// + RightTrigger = 1 << 22, + + /// + /// Left trigger button + /// + LeftTrigger = 1 << 23, + + /// + /// Right thumbstick up direction button + /// + RightThumbstickUp = 1 << 24, + + /// + /// Right thumbstick down direction button + /// + RightThumbstickDown = 1 << 25, + + /// + /// Right stick right direction button + /// + RightThumbstickRight = 1 << 26, + + /// + /// Right stick left direction button + /// + RightThumbstickLeft = 1 << 27, + + /// + /// Left stick up direction button + /// + LeftThumbstickUp = 1 << 28, + + /// + /// Left stick down direction button + /// + LeftThumbstickDown = 1 << 29, + + /// + /// Left stick right direction button + /// + LeftThumbstickRight = 1 << 30, + + /// The first button of the gamepad. + Button0 = A, + /// The second button of the gamepad. + Button1 = B, + /// The third button of the gamepad. + Button2 = X, + /// The fourth button of the gamepad. + Button3 = Y, + /// The fifth button of the gamepad. + Button4 = Start, + /// The sixth button of the gamepad. + Button5 = Back, + /// The seventh button of the gamepad. + Button6 = LeftStick, + /// The eighth button of the gamepad. + Button7 = RightStick, + /// The ninth button of the gamepad. + Button8 = LeftShoulder, + /// The tenth button of the gamepad. + Button9 = RightShoulder, + /// The eleventh button of the gamepad. + Button10 = Home, + /// The twelfth button of the gamepad. + Button11 = DPadUp, + /// The thirteenth button of the gamepad. + Button12 = DPadDown, + /// The fourteenth button of the gamepad. + Button13 = DPadLeft, + /// The fifteenth button of the gamepad. + Button14 = DPadRight, + /// The sixteenth button of the gamepad. + Button15 = LeftTrigger, + /// The seventeenth button of the gamepad. + Button16 = RightTrigger, + /// The eighteenth button of the gamepad. + Button17 = LeftThumbstickUp, + /// The nineteenth button of the gamepad. + Button18 = LeftThumbstickDown, + /// The twentieth button of the gamepad. + Button19 = LeftThumbstickLeft, + /// The twentieth-one button of the gamepad. + Button20 = LeftThumbstickRight, + /// The twentieth-one button of the gamepad. + Button21 = RightThumbstickUp, + /// The twentieth-one button of the gamepad. + Button22 = RightThumbstickDown, + /// The twentieth-one button of the gamepad. + Button23 = RightThumbstickLeft, + /// The twentieth-one button of the gamepad. + Button24 = RightThumbstickRight, + } +} diff --git a/Source/OpenTK/Input/GamePadButton.cs b/Source/OpenTK/Input/GamePadButton.cs deleted file mode 100644 index f4f543ad..00000000 --- a/Source/OpenTK/Input/GamePadButton.cs +++ /dev/null @@ -1,68 +0,0 @@ -// -// GamePadButton.cs -// -// Author: -// robert <${AuthorEmail}> -// -// Copyright (c) 2012 robert -// -// 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. -using System; - -namespace OpenTK -{ - public enum GamePadButton - { - /// The first button of the gamepad. - Button0 = 0, - /// The second button of the gamepad. - Button1, - /// The third button of the gamepad. - Button2, - /// The fourth button of the gamepad. - Button3, - /// The fifth button of the gamepad. - Button4, - /// The sixth button of the gamepad. - Button5, - /// The seventh button of the gamepad. - Button6, - /// The eighth button of the gamepad. - Button7, - /// The ninth button of the gamepad. - Button8, - /// The tenth button of the gamepad. - Button9, - /// The eleventh button of the gamepad. - Button10, - /// The twelfth button of the gamepad. - Button11, - /// The thirteenth button of the gamepad. - Button12, - /// The fourteenth button of the gamepad. - Button13, - /// The fifteenth button of the gamepad. - Button14, - /// The sixteenth button of the gamepad. - Button15, - /// The last button of the gamepad. - LastButton - } -} - diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs new file mode 100644 index 00000000..199e593f --- /dev/null +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -0,0 +1,131 @@ +// #region License +// +// GamePadButtons.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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; + +namespace OpenTK.Input +{ + + public struct GamePadButtons : IEquatable + { + Buttons buttons; + + public GamePadButtons(Buttons state) + { + buttons = state; + } + + #region Public Members + + public ButtonState A + { + get { return GetButton(Buttons.A); } + } + + public ButtonState B + { + get { return GetButton(Buttons.B); } + } + + public ButtonState X + { + get { return GetButton(Buttons.X); } + } + + public ButtonState Y + { + get { return GetButton(Buttons.Y); } + } + + public ButtonState Back + { + get { return GetButton(Buttons.Back); } + } + + public ButtonState BigButton + { + get { return GetButton(Buttons.BigButton); } + } + + public ButtonState LeftShoulder + { + get { return GetButton(Buttons.LeftShoulder); } + } + + public ButtonState LeftStick + { + get { return GetButton(Buttons.LeftStick); } + } + + public ButtonState RightShoulder + { + get { return GetButton(Buttons.RightShoulder); } + } + + public ButtonState RightStick + { + get { return GetButton(Buttons.RightStick); } + } + + public ButtonState Start + { + get { return GetButton(Buttons.Start); } + } + + public static bool operator ==(GamePadButtons left, GamePadButtons right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadButtons left, GamePadButtons right) + { + return !left.Equals(right); + } + + #endregion + + #region IEquatable Members + + public bool Equals(GamePadButtons other) + { + return buttons == other.buttons; + } + + #endregion + + #region Private Members + + ButtonState GetButton(Buttons b) + { + return (buttons & b) != 0 ? ButtonState.Pressed : ButtonState.Released; + } + + #endregion + } +} + From 2bf024a912e6aae1d69d1caee372102402a323ba Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 19 Dec 2013 16:28:20 +0100 Subject: [PATCH 075/154] Implemented new GamePad interface (WIP) --- Source/OpenTK/Input/GamePad.cs | 32 +++++-- Source/OpenTK/Input/GamePadAxis.cs | 8 +- Source/OpenTK/Input/GamePadCapabilities.cs | 67 +++++++++++++++ Source/OpenTK/Input/GamePadDPad.cs | 90 ++++++++++++++++++++ Source/OpenTK/Input/GamePadState.cs | 99 ++++++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 5 +- 6 files changed, 290 insertions(+), 11 deletions(-) create mode 100644 Source/OpenTK/Input/GamePadCapabilities.cs create mode 100644 Source/OpenTK/Input/GamePadDPad.cs diff --git a/Source/OpenTK/Input/GamePad.cs b/Source/OpenTK/Input/GamePad.cs index 303f4516..7a2fc066 100644 --- a/Source/OpenTK/Input/GamePad.cs +++ b/Source/OpenTK/Input/GamePad.cs @@ -30,17 +30,39 @@ using System; namespace OpenTK.Input { /// - /// Provides access to GamePad devices. Note: this API is not implemented yet. + /// Provides access to GamePad devices. /// public class GamePad { - #region Constructors + internal const int MaxAxisCount = 10; + internal const int MaxButtonCount = 16; // if this grows over 32 then GamePadState.buttons must be modified + internal const int MaxDPadCount = 2; - static GamePad() + static readonly IGamePadDriver driver = + Platform.Factory.Default.CreateGamePadDriver(); + + /// + /// Retrieves a GamePadCapabilities structure describing the + /// capabilities of a gamepad device. + /// + /// The zero-based index of a gamepad device. + /// A GamePadCapabilities structure describing the capabilities of the gamepad device. + public static GamePadCapabilities GetCapabilities(int index) { - throw new NotImplementedException(); + if (index < 0) + throw new IndexOutOfRangeException(); + + return driver.GetCapabilities(index); } - #endregion + /// + /// Retrieves the GamePadState for the specified gamepad device. + /// + /// The zero-based index of a gamepad device. + /// A GamePadState structure describing the state of the gamepad device. + public static GamePadState GetState(int index) + { + return driver.GetState(index); + } } } diff --git a/Source/OpenTK/Input/GamePadAxis.cs b/Source/OpenTK/Input/GamePadAxis.cs index c1c96c53..dd6b3192 100644 --- a/Source/OpenTK/Input/GamePadAxis.cs +++ b/Source/OpenTK/Input/GamePadAxis.cs @@ -25,11 +25,11 @@ // THE SOFTWARE. using System; -namespace OpenTK +namespace OpenTK.Input { public enum GamePadAxis - { - /// The first axis of the gamepad. + { + /// The first axis of the gamepad. Axis0 = 0, /// The second axis of the gamepad. Axis1, @@ -49,8 +49,6 @@ namespace OpenTK Axis8, /// The tenth axis of the gamepad. Axis9, - /// The last axis of the gamepad. - LastAxis } } diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs new file mode 100644 index 00000000..23c56cd3 --- /dev/null +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -0,0 +1,67 @@ +// #region License +// +// GamePadCapabilities.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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; + +namespace OpenTK.Input +{ + + public struct GamePadCapabilities + { + byte axis_count; + byte button_count; + byte dpad_count; + byte trackball_count; + + public int AxisCount + { + get { return axis_count; } + internal set { axis_count = (byte)value; } + } + + public int ButtonCount + { + get { return button_count; } + internal set { button_count = (byte)value; } + } + + public int DPadCount + { + get { return dpad_count; } + internal set { dpad_count = (byte)value; } + } + + public int TrackballCount + { + get { return trackball_count; } + internal set { trackball_count = (byte)value; } + } + } +} + diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs new file mode 100644 index 00000000..72389b00 --- /dev/null +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -0,0 +1,90 @@ +// #region License +// +// GamePadDPad.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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; + +namespace OpenTK.Input +{ + + public struct GamePadDPad + { + [Flags] + enum DPadButtons : byte + { + Up = Buttons.DPadUp, + Down = Buttons.DPadDown, + Left = Buttons.DPadLeft, + Right = Buttons.DPadRight + } + + DPadButtons buttons; + + internal GamePadDPad(Buttons state) + { + // DPad butons are stored in the lower 4bits + // of the Buttons enumeration. + buttons = (DPadButtons)((int)state & 0x0f); + } + + public bool IsUp + { + get { return (buttons & DPadButtons.Up) != 0; } + internal set { SetButton(DPadButtons.Up, value); } + } + + public bool IsDown + { + get { return (buttons & DPadButtons.Down) != 0; } + internal set { SetButton(DPadButtons.Down, value); } + } + + public bool IsLeft + { + get { return (buttons & DPadButtons.Left) != 0; } + internal set { SetButton(DPadButtons.Left, value); } + } + + public bool IsRight + { + get { return (buttons & DPadButtons.Right) != 0; } + internal set { SetButton(DPadButtons.Right, value); } + } + + void SetButton(DPadButtons button, bool value) + { + if (value) + { + buttons |= button; + } + else + { + buttons &= ~button; + } + } + } +} diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index 21e3aa91..d45787bb 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -34,6 +34,105 @@ namespace OpenTK.Input /// public struct GamePadState /*: IEquatable*/ { + const float RangeMultiplier = 1.0f / (short.MaxValue + 1); + Buttons buttons; + unsafe fixed short axes[GamePad.MaxAxisCount]; + bool is_connected; + + #region Public Members + + public float GetAxis(GamePadAxis axis) + { + throw new NotImplementedException(); + } + + public GamePadButtons Buttons + { + get { return new GamePadButtons(buttons); } + } + + public GamePadDPad DPad + { + get { return new GamePadDPad(buttons); } + } + + public bool IsConnected + { + get { return is_connected; } + } + + #endregion + + #region Internal Members + + internal void SetAxis(GamePadAxis axis, short value) + { + if (IsAxisValid(axis)) + { + int index = (int)axis; + unsafe + { + fixed (short *paxes = axes) + { + *(paxes + index) = value; + } + } + } + else + { + throw new ArgumentOutOfRangeException("axis"); + } + } + + internal void SetButton(Buttons button, bool pressed) + { + if (IsButtonValid(button)) + { + int index = (int)button; + + Buttons mask = (Buttons)(1 << index); + if (pressed) + { + buttons |= mask; + } + else + { + buttons &= ~mask; + } + } + else + { + throw new ArgumentOutOfRangeException("button"); + } + } + + internal void SetConnected(bool connected) + { + is_connected = connected; + } + + #endregion + + #region Private Members + + bool IsAxisValid(GamePadAxis axis) + { + int index = (int)axis; + return index >= 0 && index < GamePad.MaxAxisCount; + } + + bool IsButtonValid(Buttons button) + { + int index = (int)button; + return index >= 0 && index < GamePad.MaxButtonCount; + } + + bool IsDPadValid(int index) + { + return index >= 0 && index < GamePad.MaxDPadCount; + } + + #endregion } } diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 7bddfcb0..723b4412 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -738,7 +738,6 @@ - @@ -777,6 +776,10 @@ + + + + From 1acf8a807b374c6d5e24c354a34a5085f5f85f9c Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 22:01:04 +0100 Subject: [PATCH 076/154] Implemented IEquatable<> interface --- Source/OpenTK/Input/GamePadButtons.cs | 30 ++++++++++++- Source/OpenTK/Input/GamePadCapabilities.cs | 46 ++++++++++++++++++- Source/OpenTK/Input/GamePadDPad.cs | 51 +++++++++++++++++++++- Source/OpenTK/Input/GamePadState.cs | 32 +++++++++++++- 4 files changed, 155 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index 199e593f..5d423ddb 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -107,9 +107,37 @@ namespace OpenTK.Input return !left.Equals(right); } + public override string ToString() + { + return String.Format( + "{{ABXYLR: {0}{1}{2}{3}{4}{5}; Back: {6}; BigButton: {7}; LStick: {8}; RStick: {9}}}", + A == ButtonState.Pressed ? "1" : "0", + B == ButtonState.Pressed ? "1" : "0", + X == ButtonState.Pressed ? "1" : "0", + Y == ButtonState.Pressed ? "1" : "0", + LeftShoulder == ButtonState.Pressed ? "1" : "0", + RightShoulder == ButtonState.Pressed ? "1" : "0", + Back == ButtonState.Pressed ? "1" : "0", + BigButton == ButtonState.Pressed ? "1" : "0", + LeftStick == ButtonState.Pressed ? "1" : "0", + RightStick == ButtonState.Pressed ? "1" : "0"); + } + + public override int GetHashCode() + { + return buttons.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadButtons && + Equals((GamePadButtons)obj); + } + #endregion - #region IEquatable Members + #region IEquatable Members public bool Equals(GamePadButtons other) { diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 23c56cd3..767e0198 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -32,7 +32,7 @@ using System; namespace OpenTK.Input { - public struct GamePadCapabilities + public struct GamePadCapabilities : IEquatable { byte axis_count; byte button_count; @@ -62,6 +62,50 @@ namespace OpenTK.Input get { return trackball_count; } internal set { trackball_count = (byte)value; } } + + public static bool operator ==(GamePadCapabilities left, GamePadCapabilities right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadCapabilities left, GamePadCapabilities right) + { + return !left.Equals(right); + } + + public override string ToString() + { + return String.Format( + "{{Axes: {0}; Buttons: {1}; DPads: {2}; Trackballs: {3}}}", + AxisCount, ButtonCount, DPadCount, TrackballCount); + } + + public override int GetHashCode() + { + return + AxisCount.GetHashCode() ^ ButtonCount.GetHashCode() ^ + DPadCount.GetHashCode() ^ TrackballCount.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadCapabilities && + Equals((GamePadCapabilities)obj); + } + + #region IEquatable Members + + public bool Equals(GamePadCapabilities other) + { + return + AxisCount == other.AxisCount && + ButtonCount == other.ButtonCount && + DPadCount == other.DPadCount && + TrackballCount == other.TrackballCount; + } + + #endregion } } diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs index 72389b00..06ba2262 100644 --- a/Source/OpenTK/Input/GamePadDPad.cs +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -31,7 +31,7 @@ using System; namespace OpenTK.Input { - public struct GamePadDPad + public struct GamePadDPad : IEquatable { [Flags] enum DPadButtons : byte @@ -44,6 +44,8 @@ namespace OpenTK.Input DPadButtons buttons; + #region Public Members + internal GamePadDPad(Buttons state) { // DPad butons are stored in the lower 4bits @@ -75,6 +77,42 @@ namespace OpenTK.Input internal set { SetButton(DPadButtons.Right, value); } } + public static bool operator ==(GamePadDPad left, GamePadDPad right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadDPad left, GamePadDPad right) + { + return !left.Equals(right); + } + + public override string ToString() + { + return String.Format( + "{{ULDR: {0}{1}{2}{3}}}", + IsUp ? "1" : "0", + IsLeft ? "1" : "0", + IsDown ? "1" : "0", + IsRight ? "1" : "0"); + } + + public override int GetHashCode() + { + return buttons.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadDPad && + Equals((GamePadDPad)obj); + } + + #endregion + + #region Private Members + void SetButton(DPadButtons button, bool value) { if (value) @@ -86,5 +124,16 @@ namespace OpenTK.Input buttons &= ~button; } } + + #endregion + + #region IEquatable Members + + public bool Equals(GamePadDPad other) + { + return buttons == other.buttons; + } + + #endregion } } diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index d45787bb..e85187f8 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -32,7 +32,7 @@ namespace OpenTK.Input /// /// Encapsulates the state of a GamePad device. /// - public struct GamePadState /*: IEquatable*/ + public struct GamePadState : IEquatable { const float RangeMultiplier = 1.0f / (short.MaxValue + 1); @@ -62,6 +62,36 @@ namespace OpenTK.Input get { return is_connected; } } + public override string ToString() + { + return String.Format( + "{{Buttons: {0}; DPad: {1}; IsConnected: {2}", + Buttons, DPad, IsConnected); + } + + public override int GetHashCode() + { + return Buttons.GetHashCode() ^ DPad.GetHashCode() ^ IsConnected.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadState && + Equals((GamePadState)obj); + } + + #endregion + + #region IEquatable Members + public bool Equals(GamePadState other) + { + return + Buttons == other.Buttons && + DPad == other.DPad && + IsConnected == other.IsConnected; + } + #endregion #region Internal Members From 0c10f29bd8e5b509209b987b11305dd3c87591d4 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 22:07:30 +0100 Subject: [PATCH 077/154] More compact string representation --- Source/OpenTK/Input/GamePadButtons.cs | 22 +++++++++++----------- Source/OpenTK/Input/GamePadDPad.cs | 10 +++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index 5d423ddb..0bc2988f 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -110,17 +110,17 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{ABXYLR: {0}{1}{2}{3}{4}{5}; Back: {6}; BigButton: {7}; LStick: {8}; RStick: {9}}}", - A == ButtonState.Pressed ? "1" : "0", - B == ButtonState.Pressed ? "1" : "0", - X == ButtonState.Pressed ? "1" : "0", - Y == ButtonState.Pressed ? "1" : "0", - LeftShoulder == ButtonState.Pressed ? "1" : "0", - RightShoulder == ButtonState.Pressed ? "1" : "0", - Back == ButtonState.Pressed ? "1" : "0", - BigButton == ButtonState.Pressed ? "1" : "0", - LeftStick == ButtonState.Pressed ? "1" : "0", - RightStick == ButtonState.Pressed ? "1" : "0"); + "{{{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}}}", + A == ButtonState.Pressed ? "A" : String.Empty, + B == ButtonState.Pressed ? "B" : String.Empty, + X == ButtonState.Pressed ? "X" : String.Empty, + Y == ButtonState.Pressed ? "Y" : String.Empty, + LeftShoulder == ButtonState.Pressed ? "L" : String.Empty, + RightShoulder == ButtonState.Pressed ? "R" : String.Empty, + Back == ButtonState.Pressed ? " Back" : String.Empty, + BigButton == ButtonState.Pressed ? " Big" : String.Empty, + LeftStick == ButtonState.Pressed ? " LStick" : String.Empty, + RightStick == ButtonState.Pressed ? " RStick" : String.Empty); } public override int GetHashCode() diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs index 06ba2262..375036a2 100644 --- a/Source/OpenTK/Input/GamePadDPad.cs +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -90,11 +90,11 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{ULDR: {0}{1}{2}{3}}}", - IsUp ? "1" : "0", - IsLeft ? "1" : "0", - IsDown ? "1" : "0", - IsRight ? "1" : "0"); + "{{{0}{1}{2}{3}}}", + IsUp ? "U" : String.Empty, + IsLeft ? "L" : String.Empty, + IsDown ? "D" : String.Empty, + IsRight ? "R" : String.Empty); } public override int GetHashCode() From 18f99c2f635dd092d019996345d0f0513778b463 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 22:07:40 +0100 Subject: [PATCH 078/154] Added state information for GamePads --- Source/Examples/OpenTK/Test/GameWindowStates.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index cdb5afa2..99724300 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -239,6 +239,8 @@ namespace Examples.Tests DrawKeyboard(gfx, keyboard, line++); DrawMouse(gfx, mouse, line++); DrawJoysticks(gfx, Joysticks, line++); + + line = DrawGamePads(gfx, line); } } @@ -249,7 +251,19 @@ namespace Examples.Tests PixelType.UnsignedByte, data.Scan0); TextBitmap.UnlockBits(data); } - + + int DrawGamePads(Graphics gfx, int line) + { + DrawString(gfx, "GamePads:", line++); + for (int i = 0; i < 4; i++) + { + GamePadCapabilities caps = GamePad.GetCapabilities(i); + GamePadState state = GamePad.GetState(i); + DrawString(gfx, caps.ToString(), line++); + DrawString(gfx, state.ToString(), line++); + } + return line; + } protected override void OnLoad(EventArgs e) { From 91d248ad29aa316f390261dd39561ffa104d8277 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 22:32:18 +0100 Subject: [PATCH 079/154] Implemented GamePadThumbSticks --- Source/OpenTK/Input/GamePadAxis.cs | 28 ++---- Source/OpenTK/Input/GamePadState.cs | 50 ++++++---- Source/OpenTK/Input/GamePadThumbSticks.cs | 111 ++++++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 1 + 4 files changed, 149 insertions(+), 41 deletions(-) create mode 100644 Source/OpenTK/Input/GamePadThumbSticks.cs diff --git a/Source/OpenTK/Input/GamePadAxis.cs b/Source/OpenTK/Input/GamePadAxis.cs index dd6b3192..f619ab6a 100644 --- a/Source/OpenTK/Input/GamePadAxis.cs +++ b/Source/OpenTK/Input/GamePadAxis.cs @@ -27,28 +27,12 @@ using System; namespace OpenTK.Input { - public enum GamePadAxis + internal enum GamePadAxis { - /// The first axis of the gamepad. - Axis0 = 0, - /// The second axis of the gamepad. - Axis1, - /// The third axis of the gamepad. - Axis2, - /// The fourth axis of the gamepad. - Axis3, - /// The fifth axis of the gamepad. - Axis4, - /// The sixth axis of the gamepad. - Axis5, - /// The seventh axis of the gamepad. - Axis6, - /// The eighth axis of the gamepad. - Axis7, - /// The ninth axis of the gamepad. - Axis8, - /// The tenth axis of the gamepad. - Axis9, - } + LeftX, + LeftY, + RightX, + RightY + } } diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index e85187f8..ad603017 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -37,14 +37,17 @@ namespace OpenTK.Input const float RangeMultiplier = 1.0f / (short.MaxValue + 1); Buttons buttons; - unsafe fixed short axes[GamePad.MaxAxisCount]; + short left_stick_x; + short left_stick_y; + short right_stick_x; + short right_stick_y; bool is_connected; #region Public Members - public float GetAxis(GamePadAxis axis) + public GamePadThumbSticks ThumbSticks { - throw new NotImplementedException(); + get { return new GamePadThumbSticks(left_stick_x, left_stick_y, right_stick_x, right_stick_y); } } public GamePadButtons Buttons @@ -65,13 +68,15 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Buttons: {0}; DPad: {1}; IsConnected: {2}", - Buttons, DPad, IsConnected); + "{{Sticks: {0}; Buttons: {1}; DPad: {2}; IsConnected: {3}", + ThumbSticks, Buttons, DPad, IsConnected); } public override int GetHashCode() { - return Buttons.GetHashCode() ^ DPad.GetHashCode() ^ IsConnected.GetHashCode(); + return + ThumbSticks.GetHashCode() ^ Buttons.GetHashCode() ^ + DPad.GetHashCode() ^ IsConnected.GetHashCode(); } public override bool Equals(object obj) @@ -87,6 +92,7 @@ namespace OpenTK.Input public bool Equals(GamePadState other) { return + ThumbSticks == other.ThumbSticks && Buttons == other.Buttons && DPad == other.DPad && IsConnected == other.IsConnected; @@ -98,20 +104,26 @@ namespace OpenTK.Input internal void SetAxis(GamePadAxis axis, short value) { - if (IsAxisValid(axis)) + switch (axis) { - int index = (int)axis; - unsafe - { - fixed (short *paxes = axes) - { - *(paxes + index) = value; - } - } - } - else - { - throw new ArgumentOutOfRangeException("axis"); + case GamePadAxis.LeftX: + left_stick_x = value; + break; + + case GamePadAxis.LeftY: + left_stick_y = value; + break; + + case GamePadAxis.RightX: + right_stick_x = value; + break; + + case GamePadAxis.RightY: + right_stick_x = value; + break; + + default: + throw new ArgumentOutOfRangeException("axis"); } } diff --git a/Source/OpenTK/Input/GamePadThumbSticks.cs b/Source/OpenTK/Input/GamePadThumbSticks.cs new file mode 100644 index 00000000..e7c9d187 --- /dev/null +++ b/Source/OpenTK/Input/GamePadThumbSticks.cs @@ -0,0 +1,111 @@ +using System; +// #region License +// +// GamePadThumbSticks.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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.Collections.Generic; +using System.Text; + +namespace OpenTK.Input +{ + public struct GamePadThumbSticks : IEquatable + { + const float ConversionFactor = 1.0f / short.MaxValue; + short left_x, left_y; + short right_x, right_y; + + internal GamePadThumbSticks( + short left_x, short left_y, + short right_x, short right_y) + { + this.left_x = left_x; + this.left_y = left_y; + this.right_x = right_x; + this.right_y = right_y; + } + + #region Public Members + + public Vector2 Left + { + get { return new Vector2(left_x * ConversionFactor, left_y * ConversionFactor); } + } + + public Vector2 Right + { + get { return new Vector2(right_x * ConversionFactor, right_y * ConversionFactor); } + } + + public static bool operator ==(GamePadThumbSticks left, GamePadThumbSticks right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadThumbSticks left, GamePadThumbSticks right) + { + return !left.Equals(right); + } + + public override string ToString() + { + return String.Format( + "{{Left: {0}; Right: {1}}}", + Left, Right); + } + + public override int GetHashCode() + { + return + left_x.GetHashCode() ^ left_y.GetHashCode() ^ + right_x.GetHashCode() ^ right_y.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadThumbSticks && + Equals((GamePadThumbSticks)obj); + } + + #endregion + + #region IEquatable Members + + public bool Equals(GamePadThumbSticks other) + { + return + left_x == other.left_x && + left_y == other.left_y && + right_x == other.right_x && + right_y == other.right_y; + } + + #endregion + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 723b4412..aa83bbee 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -133,6 +133,7 @@ + From 76a35c0b918b2f5a1b1543f0832777a40c65d3fc Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 22:32:24 +0100 Subject: [PATCH 080/154] Added missing newline --- Source/OpenTK/Input/GamePadDPad.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs index 375036a2..8e1a0588 100644 --- a/Source/OpenTK/Input/GamePadDPad.cs +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -26,6 +26,7 @@ // THE SOFTWARE. // // #endregion + using System; namespace OpenTK.Input From 1ba5fd438057dac4eb52adca735c4f8245106cac Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 22:34:34 +0100 Subject: [PATCH 081/154] Cleaned up using directives --- Source/OpenTK/Input/GamePadThumbSticks.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Input/GamePadThumbSticks.cs b/Source/OpenTK/Input/GamePadThumbSticks.cs index e7c9d187..59eb4ee3 100644 --- a/Source/OpenTK/Input/GamePadThumbSticks.cs +++ b/Source/OpenTK/Input/GamePadThumbSticks.cs @@ -1,5 +1,4 @@ -using System; -// #region License +// #region License // // GamePadThumbSticks.cs // @@ -29,8 +28,7 @@ // #endregion -using System.Collections.Generic; -using System.Text; +using System; namespace OpenTK.Input { From 4a13415fc67b502494f80c0e1ca5b256f816ab71 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 22:47:50 +0100 Subject: [PATCH 082/154] Fixed x/y axis mixup. --- Source/OpenTK/Input/GamePadState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index ad603017..b0501f6c 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -119,7 +119,7 @@ namespace OpenTK.Input break; case GamePadAxis.RightY: - right_stick_x = value; + right_stick_y = value; break; default: From 3660509deefe760969bd3888248f102a40c67ae0 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 23:12:53 +0100 Subject: [PATCH 083/154] Added SDL_InitSubSystem method --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 2232e686..163d393b 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -233,6 +233,10 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_Init", ExactSpelling = true)] public static extern int Init(SystemFlags flags); + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_InitSubSystem", ExactSpelling = true)] + public static extern int InitSubSystem(SystemFlags flags); + /// /// Determines if the specified joystick is supported by the GameController API. /// From a72d70c3d01be0be043ce0ee959761c373a0d691 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 23:13:21 +0100 Subject: [PATCH 084/154] Delay joystick initialization until necessary --- Source/OpenTK/Configuration.cs | 4 ++-- Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Configuration.cs b/Source/OpenTK/Configuration.cs index 98aad59d..fcae8212 100644 --- a/Source/OpenTK/Configuration.cs +++ b/Source/OpenTK/Configuration.cs @@ -206,8 +206,8 @@ namespace OpenTK { if (!OpenTK.Platform.SDL2.SDL.WasInit(0)) { - var flags = OpenTK.Platform.SDL2.SystemFlags.EVERYTHING; - flags &= ~OpenTK.Platform.SDL2.SystemFlags.AUDIO; + var flags = + OpenTK.Platform.SDL2.SystemFlags.VIDEO | Platform.SDL2.SystemFlags.TIMER; if (OpenTK.Platform.SDL2.SDL.Init(flags) == 0) { supported = true; diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index de174875..d2fa0093 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -59,6 +59,7 @@ namespace OpenTK.Platform.SDL2 driver_handle = new IntPtr(count++); DriverHandles.Add(driver_handle, this); SDL.AddEventWatch(EventFilterDelegate, driver_handle); + SDL.InitSubSystem(SystemFlags.JOYSTICK | SystemFlags.GAMECONTROLLER); } } From 1d61bd9dd2d14814c9f3cc93a35dc238400796c9 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 23:54:55 +0100 Subject: [PATCH 085/154] Reuse Sdl2Factory.InputDriver in Sdl2NativeWindow --- Source/OpenTK/Platform/SDL2/Sdl2Factory.cs | 4 ++-- Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs index 9f2447ba..4c39156f 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs @@ -34,7 +34,7 @@ namespace OpenTK.Platform.SDL2 { class Sdl2Factory : IPlatformFactory { - readonly IInputDriver2 InputDriver = new Sdl2InputDriver(); + readonly Sdl2InputDriver InputDriver = new Sdl2InputDriver(); bool disposed; /// @@ -58,7 +58,7 @@ namespace OpenTK.Platform.SDL2 public 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); + return new Sdl2NativeWindow(x, y, width, height, title, options, device, InputDriver); } public IDisplayDeviceDriver CreateDisplayDeviceDriver() diff --git a/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs b/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs index dd26d534..9f24fdf7 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs @@ -70,7 +70,7 @@ namespace OpenTK.Platform.SDL2 // Argument for KeyDown and KeyUp events (allocated once to avoid runtime allocations) readonly KeyboardKeyEventArgs key_args = new KeyboardKeyEventArgs(); - readonly IInputDriver input_driver = new Sdl2InputDriver(); + readonly IInputDriver input_driver; readonly EventFilter EventFilterDelegate_GCUnsafe = FilterEvents; readonly IntPtr EventFilterDelegate; @@ -81,10 +81,13 @@ namespace OpenTK.Platform.SDL2 static readonly Sdl2KeyMap map = new Sdl2KeyMap(); public Sdl2NativeWindow(int x, int y, int width, int height, - string title, GameWindowFlags options, DisplayDevice device) + string title, GameWindowFlags options, DisplayDevice device, + IInputDriver input_driver) { lock (sync) { + this.input_driver = input_driver; + var bounds = device.Bounds; var flags = TranslateFlags(options); flags |= WindowFlags.OPENGL; From 2f1a81da2c57d85e04bd5e1a304cb056cff8ccc6 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 23:55:28 +0100 Subject: [PATCH 086/154] Log errors in subsystem initialization --- Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index d2fa0093..3a69be40 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -59,7 +59,14 @@ namespace OpenTK.Platform.SDL2 driver_handle = new IntPtr(count++); DriverHandles.Add(driver_handle, this); SDL.AddEventWatch(EventFilterDelegate, driver_handle); - SDL.InitSubSystem(SystemFlags.JOYSTICK | SystemFlags.GAMECONTROLLER); + if (SDL.InitSubSystem(SystemFlags.JOYSTICK) < 0) + { + Debug.Print("[SDL2] InputDriver failed to init Joystick subsystem. Error: {0}", SDL.GetError()); + } + if (SDL.InitSubSystem(SystemFlags.GAMECONTROLLER) < 0) + { + Debug.Print("[SDL2] InputDriver failed to init GameController subsystem. Error: {0}", SDL.GetError()); + } } } From 31ce400a7e206e41564e35227570d8ff90cdeac6 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Sun, 22 Dec 2013 23:55:46 +0100 Subject: [PATCH 087/154] Fixed expansion of joysticks collection --- Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 2af3f977..ea0f2433 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -55,7 +55,7 @@ namespace OpenTK.Platform.SDL2 } } - readonly List joysticks = new List(); + readonly List joysticks = new List(4); readonly Dictionary controllers = new Dictionary(); IList joysticks_readonly; @@ -131,16 +131,18 @@ namespace OpenTK.Platform.SDL2 case EventType.JOYDEVICEADDED: { // Make sure we have enough space to store this instance - if (joysticks.Count <= id) + if (joysticks.Capacity <= id) { - joysticks.Capacity = OpenTK.MathHelper.NextPowerOfTwo(id); + joysticks.Capacity = OpenTK.MathHelper.NextPowerOfTwo(id + 1); + for (int i = joysticks.Count; i < joysticks.Capacity; i++) + joysticks.Add(null); // Expand the joysticks list } IntPtr handle = SDL.JoystickOpen(id); if (handle != IntPtr.Zero) { JoystickDevice joystick = OpenJoystick(id); - if (joysticks != null) + if (joystick != null) { joystick.Details.IsConnected = true; joysticks[id] = joystick; From 44351a03c4249689c6c8573244d0861154a01552 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Mon, 23 Dec 2013 00:17:13 +0100 Subject: [PATCH 088/154] More robust handling of device add/remove events --- .../Platform/SDL2/Sdl2JoystickDriver.cs | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index ea0f2433..6c7e2728 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -56,6 +56,7 @@ namespace OpenTK.Platform.SDL2 } readonly List joysticks = new List(4); + readonly Dictionary sdl_joyid_to_joysticks = new Dictionary(); readonly Dictionary controllers = new Dictionary(); IList joysticks_readonly; @@ -130,14 +131,6 @@ namespace OpenTK.Platform.SDL2 { case EventType.JOYDEVICEADDED: { - // Make sure we have enough space to store this instance - if (joysticks.Capacity <= id) - { - joysticks.Capacity = OpenTK.MathHelper.NextPowerOfTwo(id + 1); - for (int i = joysticks.Count; i < joysticks.Capacity; i++) - joysticks.Add(null); // Expand the joysticks list - } - IntPtr handle = SDL.JoystickOpen(id); if (handle != IntPtr.Zero) { @@ -145,7 +138,13 @@ namespace OpenTK.Platform.SDL2 if (joystick != null) { joystick.Details.IsConnected = true; - joysticks[id] = joystick; + if (!sdl_joyid_to_joysticks.ContainsKey(id)) + { + sdl_joyid_to_joysticks.Add(id, joysticks.Count); + joysticks.Add(null); + } + int index = sdl_joyid_to_joysticks[id]; + joysticks[index] = joystick; } } } @@ -153,7 +152,8 @@ namespace OpenTK.Platform.SDL2 case EventType.JOYDEVICEREMOVED: { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; joystick.Details.IsConnected = false; } break; @@ -165,7 +165,8 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsJoystickValid(id)) { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; float value = ev.Value * RangeMultiplier; joystick.SetAxis((JoystickAxis)ev.Axis, value); } @@ -180,7 +181,8 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsJoystickValid(id)) { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; // Todo: does it make sense to support balls? } else @@ -194,7 +196,8 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsJoystickValid(id)) { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; joystick.SetButton((JoystickButton)ev.Button, ev.State == State.Pressed); } else @@ -208,7 +211,8 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsJoystickValid(id)) { - JoystickDevice joystick = (JoystickDevice)joysticks[id]; + int index = sdl_joyid_to_joysticks[id]; + JoystickDevice joystick = (JoystickDevice)joysticks[index]; // Todo: map hat to an extra axis } else @@ -224,15 +228,15 @@ namespace OpenTK.Platform.SDL2 switch (ev.Type) { case EventType.CONTROLLERDEVICEADDED: - if (SDL.IsGameController(id)) + IntPtr handle = SDL.GameControllerOpen(id); + if (handle != IntPtr.Zero) { - IntPtr handle = SDL.GameControllerOpen(id); - if (handle != IntPtr.Zero) - { - Sdl2GamePad pad = new Sdl2GamePad(handle); - pad.State.SetConnected(true); - controllers.Add(id, pad); - } + Sdl2GamePad pad = new Sdl2GamePad(handle); + pad.State.SetConnected(true); + // Check whether the device has ever been connected before + if (!controllers.ContainsKey(id)) + controllers.Add(id, null); + controllers[id] = pad; } break; From 0c9a67da411310f3f7f158a503d881ae8c0d04bd Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Mon, 23 Dec 2013 01:29:12 +0100 Subject: [PATCH 089/154] Fixed rendering of joysticks and gamepads Joysticks and gamepad states would overlap, causing some lines to be unreadable. This is now fixed. --- Source/Examples/OpenTK/Test/GameWindowStates.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 99724300..cc3b29b1 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -163,7 +163,7 @@ namespace Examples.Tests } } - static void DrawJoysticks(Graphics gfx, IList joysticks, int line) + static int DrawJoysticks(Graphics gfx, IList joysticks, int line) { float space = gfx.MeasureString(" ", TextFont).Width; @@ -192,6 +192,8 @@ namespace Examples.Tests line++; } + + return line; } protected override void OnUpdateFrame(FrameEventArgs e) @@ -238,9 +240,8 @@ namespace Examples.Tests DrawString(gfx, TypedText.ToString(), line++); DrawKeyboard(gfx, keyboard, line++); DrawMouse(gfx, mouse, line++); - DrawJoysticks(gfx, Joysticks, line++); - - line = DrawGamePads(gfx, line); + line = DrawJoysticks(gfx, Joysticks, line++); + line = DrawGamePads(gfx, line++); } } From 1adc3f77331bf1c01f7b00638bb64b22d7b49319 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Mon, 23 Dec 2013 01:49:49 +0100 Subject: [PATCH 090/154] Display start button in ToString() --- Source/OpenTK/Input/GamePadButtons.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index 0bc2988f..aeb97b59 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -118,6 +118,7 @@ namespace OpenTK.Input LeftShoulder == ButtonState.Pressed ? "L" : String.Empty, RightShoulder == ButtonState.Pressed ? "R" : String.Empty, Back == ButtonState.Pressed ? " Back" : String.Empty, + Start == ButtonState.Pressed ? " Start" : String.Empty, BigButton == ButtonState.Pressed ? " Big" : String.Empty, LeftStick == ButtonState.Pressed ? " LStick" : String.Empty, RightStick == ButtonState.Pressed ? " RStick" : String.Empty); From 0875cbd9285ed51c12948fc418c5baf6d6b23ea1 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Mon, 23 Dec 2013 01:50:13 +0100 Subject: [PATCH 091/154] Removed unnecessary IsButtonValid method --- Source/OpenTK/Input/GamePad.cs | 1 - Source/OpenTK/Input/GamePadState.cs | 22 +++------------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/Source/OpenTK/Input/GamePad.cs b/Source/OpenTK/Input/GamePad.cs index 7a2fc066..a0a63f49 100644 --- a/Source/OpenTK/Input/GamePad.cs +++ b/Source/OpenTK/Input/GamePad.cs @@ -35,7 +35,6 @@ namespace OpenTK.Input public class GamePad { internal const int MaxAxisCount = 10; - internal const int MaxButtonCount = 16; // if this grows over 32 then GamePadState.buttons must be modified internal const int MaxDPadCount = 2; static readonly IGamePadDriver driver = diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index b0501f6c..ceec371f 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -129,23 +129,13 @@ namespace OpenTK.Input internal void SetButton(Buttons button, bool pressed) { - if (IsButtonValid(button)) + if (pressed) { - int index = (int)button; - - Buttons mask = (Buttons)(1 << index); - if (pressed) - { - buttons |= mask; - } - else - { - buttons &= ~mask; - } + buttons |= button; } else { - throw new ArgumentOutOfRangeException("button"); + buttons &= ~button; } } @@ -164,12 +154,6 @@ namespace OpenTK.Input return index >= 0 && index < GamePad.MaxAxisCount; } - bool IsButtonValid(Buttons button) - { - int index = (int)button; - return index >= 0 && index < GamePad.MaxButtonCount; - } - bool IsDPadValid(int index) { return index >= 0 && index < GamePad.MaxDPadCount; From 5d88a8daf4879d139c3e0608ab0e60d38df9aaaa Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Mon, 23 Dec 2013 01:50:25 +0100 Subject: [PATCH 092/154] Implemented GamePad API (WIP) --- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 61 ++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index ca229700..07c208cc 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -133,6 +133,11 @@ namespace OpenTK.Platform.Windows return stick; } + bool IsValid(int index) + { + return index >= 0 && index < UnsafeNativeMethods.joyGetNumDevs(); + } + #endregion #region IJoystickDriver @@ -432,12 +437,64 @@ namespace OpenTK.Platform.Windows public GamePadCapabilities GetCapabilities(int index) { - throw new NotImplementedException(); + GamePadCapabilities gpcaps = new GamePadCapabilities(); + + if (IsValid(index)) + { + JoyCaps caps; + JoystickError result = UnsafeNativeMethods.joyGetDevCaps(index, out caps, JoyCaps.SizeInBytes); + if (result == JoystickError.NoError) + { + gpcaps.AxisCount = caps.NumAxes; + gpcaps.ButtonCount = caps.NumButtons; + if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) + gpcaps.DPadCount++; + } + } + else + { + Debug.Print("[Win] Invalid WinMM joystick device {0}", index); + } + + return gpcaps; } public GamePadState GetState(int index) { - throw new NotImplementedException(); + GamePadState state = new GamePadState(); + + if (IsValid(index)) + { + JoyInfoEx info = new JoyInfoEx(); + info.Size = JoyInfoEx.SizeInBytes; + info.Flags = JoystickFlags.All; + UnsafeNativeMethods.joyGetPosEx(index, ref info); + + state.SetAxis(GamePadAxis.LeftX, (short)info.XPos); + state.SetAxis(GamePadAxis.LeftY, (short)info.YPos); + state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); + state.SetAxis(GamePadAxis.RightY, (short)info.RPos); + //state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); + //state.SetAxis(GamePadAxis.RightY, (short)info.RPos); + + state.SetButton(Buttons.A, (info.Buttons & 1 << 0) != 0); + state.SetButton(Buttons.B, (info.Buttons & 1 << 1) != 0); + state.SetButton(Buttons.X, (info.Buttons & 1 << 2) != 0); + state.SetButton(Buttons.Y, (info.Buttons & 1 << 3) != 0); + state.SetButton(Buttons.LeftShoulder, (info.Buttons & 1 << 4) != 0); + state.SetButton(Buttons.RightShoulder, (info.Buttons & 1 << 5) != 0); + state.SetButton(Buttons.Back, (info.Buttons & 1 << 6) != 0); + state.SetButton(Buttons.Start, (info.Buttons & 1 << 7) != 0); + state.SetButton(Buttons.LeftStick, (info.Buttons & 1 << 8) != 0); + state.SetButton(Buttons.RightStick, (info.Buttons & 1 << 9) != 0); + state.SetButton(Buttons.BigButton, (info.Buttons & 1 << 10) != 0); + } + else + { + Debug.Print("[Win] Invalid WinMM joystick device {0}", index); + } + + return state; } public string GetName(int index) From 8f7eebb58d3213c15a683447698b800e75a08cee Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 23 Dec 2013 19:19:41 +0100 Subject: [PATCH 093/154] Enabled HIDInput IGamePadDriver implementation --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index 8e3c6011..c3e55612 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -50,7 +50,7 @@ namespace OpenTK.Platform.MacOS // Requires Mac OS X 10.5 or higher. // Todo: create a driver for older installations. Maybe use CGGetLastMouseDelta for that? - class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2/*, IGamePadDriver*/ + class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IGamePadDriver { #region Fields @@ -291,7 +291,7 @@ namespace OpenTK.Platform.MacOS public IMouseDriver2 MouseDriver { get { return this; } } public IKeyboardDriver2 KeyboardDriver { get { return this; } } - public IGamePadDriver GamePadDriver { get { throw new NotImplementedException(); } } + public IGamePadDriver GamePadDriver { get { return this; } } #endregion @@ -366,6 +366,25 @@ namespace OpenTK.Platform.MacOS #endregion + #region IGamePadDriver Members + + public GamePadState GetState(int index) + { + return new GamePadState(); + } + + public GamePadCapabilities GetCapabilities(int index) + { + return new GamePadCapabilities(); + } + + public string GetName(int index) + { + throw new NotImplementedException(); + } + + #endregion + #region NativeMethods class NativeMethods From dd648a836262ded283bc1d4a5c89c17d56e5c3d0 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Mon, 23 Dec 2013 20:30:58 +0100 Subject: [PATCH 094/154] Initial implementation of GamePadTriggers --- Source/OpenTK/Input/GamePadTriggers.cs | 102 +++++++++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 1 + 2 files changed, 103 insertions(+) create mode 100644 Source/OpenTK/Input/GamePadTriggers.cs diff --git a/Source/OpenTK/Input/GamePadTriggers.cs b/Source/OpenTK/Input/GamePadTriggers.cs new file mode 100644 index 00000000..ecff49c7 --- /dev/null +++ b/Source/OpenTK/Input/GamePadTriggers.cs @@ -0,0 +1,102 @@ +// #region License +// +// GamePadTriggers.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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; + +namespace OpenTK.Input +{ + public struct GamePadTriggers : IEquatable + { + const float ConversionFactor = 1.0f / short.MaxValue; + short left; + short right; + + internal GamePadTriggers(short left, short right) + { + this.left = left; + this.right = right; + } + + #region Public Members + + public float Left + { + get { return left * ConversionFactor; } + } + + public float Right + { + get { return right * ConversionFactor; } + } + + public static bool operator ==(GamePadTriggers left, GamePadTriggers right) + { + return left.Equals(right); + } + + public static bool operator !=(GamePadTriggers left, GamePadTriggers right) + { + return !left.Equals(right); + } + + public override string ToString() + { + return String.Format( + "{{Left: {0}; Right: {1}}}", + Left, Right); + } + + public override int GetHashCode() + { + return + left.GetHashCode() ^ right.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is GamePadTriggers && + Equals((GamePadTriggers)obj); + } + + #endregion + + #region IEquatable Members + + public bool Equals(GamePadTriggers other) + { + return + left == other.left && + right == other.right; + } + + #endregion + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index aa83bbee..629191e5 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -134,6 +134,7 @@ + From ea3c9ffe8599aeab49e73d0881ca1e4bddd56637 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Mon, 23 Dec 2013 22:00:10 +0100 Subject: [PATCH 095/154] Refresh text continuously --- .../Examples/OpenTK/Test/GameWindowStates.cs | 67 ++++++++----------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index cc3b29b1..15be8241 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -25,9 +25,8 @@ namespace Examples.Tests int texture; bool mouse_in_window = false; bool viewport_changed = true; - bool refresh_text = true; - MouseState mouse, mouse_old; - KeyboardState keyboard, keyboard_old; + MouseState mouse; + KeyboardState keyboard; public GameWindowStates() : base(800, 600, GraphicsMode.Default) @@ -197,52 +196,40 @@ namespace Examples.Tests } protected override void OnUpdateFrame(FrameEventArgs e) - {; + { InputDriver.Poll(); mouse = OpenTK.Input.Mouse.GetState(); - if (mouse != mouse_old) - refresh_text = true; - mouse_old = mouse; - keyboard = OpenTK.Input.Keyboard.GetState(); - if (keyboard != keyboard_old) - refresh_text = true; - keyboard_old = keyboard; - if (refresh_text) + using (Graphics gfx = Graphics.FromImage(TextBitmap)) { - refresh_text = false; - - using (Graphics gfx = Graphics.FromImage(TextBitmap)) - { - int line = 0; + int line = 0; - gfx.Clear(Color.Black); - gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + gfx.Clear(Color.Black); + gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; - DrawString(gfx, GL.GetString(StringName.Vendor), line++); - DrawString(gfx, GL.GetString(StringName.Version), line++); - DrawString(gfx, GL.GetString(StringName.Renderer), line++); - DrawString(gfx, Context.GraphicsMode.ToString(), line++); + DrawString(gfx, GL.GetString(StringName.Vendor), line++); + DrawString(gfx, GL.GetString(StringName.Version), line++); + DrawString(gfx, GL.GetString(StringName.Renderer), line++); + DrawString(gfx, Context.GraphicsMode.ToString(), line++); - DrawString(gfx, String.Format("[1 - 4]: change WindowState (current: {0}).", this.WindowState), line++); - DrawString(gfx, String.Format("[5 - 7]: change WindowBorder (current: {0}).", this.WindowBorder), line++); - DrawString(gfx, String.Format("Focused: {0}.", this.Focused), line++); - DrawString(gfx, String.Format("Mouse {0} window.", mouse_in_window ? "inside" : "outside of"), line++); - DrawString(gfx, String.Format("Mouse visible: {0}", CursorVisible), line++); - DrawString(gfx, String.Format("Mouse position (absolute): {0}", new Vector3(Mouse.X, Mouse.Y, Mouse.Wheel)), line++); - DrawString(gfx, String.Format("Mouse position (relative): {0}", new Vector3(mouse.X, mouse.Y, mouse.WheelPrecise)), line++); - DrawString(gfx, String.Format("Window.Bounds: {0}", Bounds), line++); - DrawString(gfx, String.Format("Window.Location: {0}, Size: {1}", Location, Size), line++); - DrawString(gfx, String.Format("Window: {{X={0},Y={1},Width={2},Height={3}}}", X, Y, Width, Height), line++); - DrawString(gfx, String.Format("Window.ClientRectangle: {0}", ClientRectangle), line++); - DrawString(gfx, TypedText.ToString(), line++); - DrawKeyboard(gfx, keyboard, line++); - DrawMouse(gfx, mouse, line++); - line = DrawJoysticks(gfx, Joysticks, line++); - line = DrawGamePads(gfx, line++); - } + DrawString(gfx, String.Format("[1 - 4]: change WindowState (current: {0}).", this.WindowState), line++); + DrawString(gfx, String.Format("[5 - 7]: change WindowBorder (current: {0}).", this.WindowBorder), line++); + DrawString(gfx, String.Format("Focused: {0}.", this.Focused), line++); + DrawString(gfx, String.Format("Mouse {0} window.", mouse_in_window ? "inside" : "outside of"), line++); + DrawString(gfx, String.Format("Mouse visible: {0}", CursorVisible), line++); + DrawString(gfx, String.Format("Mouse position (absolute): {0}", new Vector3(Mouse.X, Mouse.Y, Mouse.Wheel)), line++); + DrawString(gfx, String.Format("Mouse position (relative): {0}", new Vector3(mouse.X, mouse.Y, mouse.WheelPrecise)), line++); + DrawString(gfx, String.Format("Window.Bounds: {0}", Bounds), line++); + DrawString(gfx, String.Format("Window.Location: {0}, Size: {1}", Location, Size), line++); + DrawString(gfx, String.Format("Window: {{X={0},Y={1},Width={2},Height={3}}}", X, Y, Width, Height), line++); + DrawString(gfx, String.Format("Window.ClientRectangle: {0}", ClientRectangle), line++); + DrawString(gfx, TypedText.ToString(), line++); + DrawKeyboard(gfx, keyboard, line++); + DrawMouse(gfx, mouse, line++); + line = DrawJoysticks(gfx, Joysticks, line++); + line = DrawGamePads(gfx, line++); } System.Drawing.Imaging.BitmapData data = TextBitmap.LockBits( From ddc52ce13524f2c1fd45c34a2241877cc6639ef8 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 00:15:28 +0100 Subject: [PATCH 096/154] Implemented GamePad Capabilities and Type --- Source/OpenTK/Input/GamePadCapabilities.cs | 194 ++++++++++++++++++--- Source/OpenTK/Input/GamePadType.cs | 45 +++++ Source/OpenTK/OpenTK.csproj | 1 + 3 files changed, 220 insertions(+), 20 deletions(-) create mode 100644 Source/OpenTK/Input/GamePadType.cs diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 767e0198..16707aba 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -39,28 +39,152 @@ namespace OpenTK.Input byte dpad_count; byte trackball_count; - public int AxisCount + Buttons buttons; + byte gamepad_type; + bool is_connected; + + #region Constructors + + public GamePadCapabilities(GamePadType type, Buttons buttons, bool is_connected) + : this() { - get { return axis_count; } - internal set { axis_count = (byte)value; } + gamepad_type = (byte)type; + this.buttons = buttons; + this.is_connected = is_connected; } - public int ButtonCount + #endregion + + #region Public Members + + public GamePadType GamePadType { - get { return button_count; } - internal set { button_count = (byte)value; } + get { return (GamePadType)gamepad_type; } } - public int DPadCount + public bool HasDPadUpButton { - get { return dpad_count; } - internal set { dpad_count = (byte)value; } + get { return (buttons & Buttons.DPadUp) != 0; } } - public int TrackballCount + public bool HasDPadLeftButton { - get { return trackball_count; } - internal set { trackball_count = (byte)value; } + get { return (buttons & Buttons.DPadLeft) != 0; } + } + + public bool HasDPadDownButton + { + get { return (buttons & Buttons.DPadDown) != 0; } + } + + public bool HasDPadRightButton + { + get { return (buttons & Buttons.DPadRight) != 0; } + } + + public bool HasAButton + { + get { return (buttons & Buttons.A) != 0; } + } + + public bool HasBButton + { + get { return (buttons & Buttons.B) != 0; } + } + + public bool HasXButton + { + get { return (buttons & Buttons.X) != 0; } + } + + public bool HasYButton + { + get { return (buttons & Buttons.Y) != 0; } + } + + public bool HasLeftStickButton + { + get { return (buttons & Buttons.LeftStick) != 0; } + } + + public bool HasRightStickButton + { + get { return (buttons & Buttons.RightStick) != 0; } + } + + public bool HasLeftShoulderButton + { + get { return (buttons & Buttons.LeftShoulder) != 0; } + } + + public bool HasRightShoulderButton + { + get { return (buttons & Buttons.RightShoulder) != 0; } + } + + public bool HasBackButton + { + get { return (buttons & Buttons.Back) != 0; } + } + + public bool HasBigButton + { + get { return (buttons & Buttons.BigButton) != 0; } + } + + public bool HasStartButton + { + get { return (buttons & Buttons.Start) != 0; } + } + + public bool HasLeftXThumbStick + { + get { return false; } + } + + public bool HasLeftYThumbStick + { + get { return false; } + } + + public bool HasRightXThumbStick + { + get { return false; } + } + + public bool HasRightYThumbStick + { + get { return false; } + } + + public bool HasLeftTrigger + { + get { return false; } + } + + public bool HasRightTrigger + { + get { return false; } + } + + public bool HasLeftVibrationMotor + { + get { return false; } + } + + public bool HasRightVibrationMotor + { + get { return false; } + } + + public bool HasVoiceSupport + { + get { return false; } + } + + public bool IsConnected + { + get { return is_connected; } } public static bool operator ==(GamePadCapabilities left, GamePadCapabilities right) @@ -76,15 +200,16 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Axes: {0}; Buttons: {1}; DPads: {2}; Trackballs: {3}}}", - AxisCount, ButtonCount, DPadCount, TrackballCount); + "{{Type: {0}; Buttons: {1}; Connected: {2}}}", + GamePadType, Convert.ToString((int)buttons, 2), IsConnected); } public override int GetHashCode() { return - AxisCount.GetHashCode() ^ ButtonCount.GetHashCode() ^ - DPadCount.GetHashCode() ^ TrackballCount.GetHashCode(); + buttons.GetHashCode() ^ + is_connected.GetHashCode() ^ + gamepad_type.GetHashCode(); } public override bool Equals(object obj) @@ -94,15 +219,44 @@ namespace OpenTK.Input Equals((GamePadCapabilities)obj); } + #endregion + + #region Internal Members + + internal int AxisCount + { + get { return axis_count; } + set { axis_count = (byte)value; } + } + + internal int ButtonCount + { + get { return button_count; } + set { button_count = (byte)value; } + } + + internal int DPadCount + { + get { return dpad_count; } + set { dpad_count = (byte)value; } + } + + internal int TrackballCount + { + get { return trackball_count; } + set { trackball_count = (byte)value; } + } + + #endregion + #region IEquatable Members public bool Equals(GamePadCapabilities other) { return - AxisCount == other.AxisCount && - ButtonCount == other.ButtonCount && - DPadCount == other.DPadCount && - TrackballCount == other.TrackballCount; + buttons == other.buttons && + is_connected == other.is_connected && + gamepad_type == other.gamepad_type; } #endregion diff --git a/Source/OpenTK/Input/GamePadType.cs b/Source/OpenTK/Input/GamePadType.cs new file mode 100644 index 00000000..a4eddef8 --- /dev/null +++ b/Source/OpenTK/Input/GamePadType.cs @@ -0,0 +1,45 @@ +// #region License +// +// GamePadType.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 + +namespace OpenTK.Input +{ + public enum GamePadType + { + Unknown = 0, + ArcadeStick, + DancePad, + FlightStick, + Guitar, + Wheel, + AlternateGuitar, + BigButtonPad, + DrumKit, + GamePad, + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 629191e5..81fec8c7 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -135,6 +135,7 @@ + From f459647613aee230dd16fc5aa52db5560ac290f4 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 00:15:43 +0100 Subject: [PATCH 097/154] Removed all instances of refresh_text --- Source/Examples/OpenTK/Test/GameWindowStates.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 15be8241..8359a552 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -39,20 +39,9 @@ namespace Examples.Tests MouseEnter += delegate { mouse_in_window = true; }; MouseLeave += delegate { mouse_in_window = false; }; - Move += delegate { refresh_text = true; }; - Resize += delegate { refresh_text = true; }; - WindowBorderChanged += delegate { refresh_text = true; }; - WindowStateChanged += delegate { refresh_text = true; }; - FocusedChanged += delegate { refresh_text = true; }; Mouse.Move += MouseMoveHandler; Mouse.ButtonDown += MouseButtonHandler; Mouse.ButtonUp += MouseButtonHandler; - foreach (var joystick in Joysticks) - { - joystick.Move += delegate { refresh_text = true; }; - joystick.ButtonDown += delegate { refresh_text = true; }; - joystick.ButtonUp += delegate { refresh_text = true; }; - } } private void KeyPressHandler(object sender, KeyPressEventArgs e) @@ -98,13 +87,10 @@ namespace Examples.Tests void MouseMoveHandler(object sender, MouseMoveEventArgs e) { - refresh_text = true; } void MouseButtonHandler(object sender, MouseButtonEventArgs e) { - refresh_text = true; - if (e.Button == MouseButton.Left && e.IsPressed) { CursorVisible = false; From b62f5993d486027d9f4ac4672c522d526adf05e7 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 01:36:44 +0100 Subject: [PATCH 098/154] Added missing left/right triggers --- Source/OpenTK/Input/GamePadState.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index ceec371f..22111b53 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -41,6 +41,8 @@ namespace OpenTK.Input short left_stick_y; short right_stick_x; short right_stick_y; + byte left_trigger; + byte right_trigger; bool is_connected; #region Public Members From e2d86fdf5221b43c90b1d2fe79a1896e5f956f7a Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 01:37:34 +0100 Subject: [PATCH 099/154] Implemented initial XInput IGamePadDriver --- Source/OpenTK/OpenTK.csproj | 1 + .../OpenTK/Platform/Windows/XInputJoystick.cs | 299 ++++++++++++++++++ 2 files changed, 300 insertions(+) create mode 100644 Source/OpenTK/Platform/Windows/XInputJoystick.cs diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 81fec8c7..c7de48e4 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -158,6 +158,7 @@ + Code diff --git a/Source/OpenTK/Platform/Windows/XInputJoystick.cs b/Source/OpenTK/Platform/Windows/XInputJoystick.cs new file mode 100644 index 00000000..f3e0c04e --- /dev/null +++ b/Source/OpenTK/Platform/Windows/XInputJoystick.cs @@ -0,0 +1,299 @@ +// #region License +// +// XInputJoystick.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; +using OpenTK.Input; +using System.Runtime.InteropServices; +using System.Security; + +namespace OpenTK.Platform.Windows +{ + class XInputJoystick : IGamePadDriver + { + #region IGamePadDriver Members + + public GamePadState GetState(int index) + { + XInputState xstate; + XInput910.GetState((XInputUserIndex)index, out xstate); + + GamePadState state = new GamePadState(); + state.SetButton(Buttons.A, (xstate.GamePad.Buttons & XInputButtons.A) != 0); + state.SetButton(Buttons.B, (xstate.GamePad.Buttons & XInputButtons.B) != 0); + state.SetButton(Buttons.X, (xstate.GamePad.Buttons & XInputButtons.X) != 0); + state.SetButton(Buttons.Y, (xstate.GamePad.Buttons & XInputButtons.Y) != 0); + state.SetButton(Buttons.Start, (xstate.GamePad.Buttons & XInputButtons.Start) != 0); + state.SetButton(Buttons.Back, (xstate.GamePad.Buttons & XInputButtons.Back) != 0); + //state.SetButton(Buttons.BigButton, (xstate.GamePad.Buttons & XInputButtons.???) != 0); + state.SetButton(Buttons.LeftShoulder, (xstate.GamePad.Buttons & XInputButtons.LeftShoulder) != 0); + state.SetButton(Buttons.RightShoulder, (xstate.GamePad.Buttons & XInputButtons.RightShoulder) != 0); + state.SetButton(Buttons.LeftStick, (xstate.GamePad.Buttons & XInputButtons.LeftThumb) != 0); + state.SetButton(Buttons.RightStick, (xstate.GamePad.Buttons & XInputButtons.RightThumb) != 0); + state.SetButton(Buttons.DPadDown, (xstate.GamePad.Buttons & XInputButtons.DPadDown) != 0); + state.SetButton(Buttons.DPadUp, (xstate.GamePad.Buttons & XInputButtons.DPadUp) != 0); + state.SetButton(Buttons.DPadLeft, (xstate.GamePad.Buttons & XInputButtons.DPadLeft) != 0); + state.SetButton(Buttons.DPadRight, (xstate.GamePad.Buttons & XInputButtons.DPadRight) != 0); + + return state; + } + + public GamePadCapabilities GetCapabilities(int index) + { + throw new NotImplementedException(); + } + + public string GetName(int index) + { + throw new NotImplementedException(); + } + + #endregion + + #region Private Members + + enum XInputErrorCode + { + Success = 0, + DeviceNotConnected + } + + enum XInputType + { + GamePad + } + + enum XInputSubType + { + Unknown = 0, + GamePad = 1, + Wheel = 2, + ArcadeStick = 3, + FlightStick = 4, + DancePad = 5, + Guitar = 6, + GuitarAlternate = 7, + DrumKit = 8, + GuitarBass = 0xb, + ArcadePad = 0x13 + } + + enum XInputCapabilities + { + Ffb = 0x0001, + Wireless = 0x0002, + Voice = 0x0004, + Pmd = 0x0008, + NoNavigation = 0x0010, + } + + enum XInputButtons : ushort + { + DPadUp = 0x0001, + DPadDown = 0x0002, + DPadLeft = 0x0004, + DPadRight = 0x0008, + Start = 0x0010, + Back = 0x0020, + LeftThumb = 0x0040, + RightThumb = 0x0080, + LeftShoulder = 0x0100, + RightShoulder = 0x0200, + A = 0x1000, + B = 0x2000, + X = 0x4000, + Y = 0x8000 + } + + [Flags] + enum XInputCapabilitiesFlags + { + Default = 0, + GamePadOnly = 1 + } + + enum XInputBatteryType : byte + { + Disconnected = 0x00, + Wired = 0x01, + Alkaline = 0x02, + NiMH = 0x03, + Unknown = 0xff + } + + enum XInputBatteryLevel : byte + { + Empty = 0x00, + Low = 0x01, + Medium = 0x02, + Full = 0x03 + } + + enum XInputUserIndex + { + First = 0, + Second, + Third, + Fourth, + Any = 0xff + } + + struct XInputThresholds + { + public const int LeftThumbDeadzone = 7849; + public const int RightThumbDeadzone = 8689; + public const int TriggerThreshold = 30; + } + + struct XInputGamePad + { + public XInputButtons Buttons; + public byte LeftTrigger; + public byte RightTrigger; + public short ThumbLX; + public short ThumbLY; + public short ThumbRX; + public short ThumbRY; + } + + struct XInputState + { + public int PacketNumber; + public XInputGamePad GamePad; + } + + struct XInputVibration + { + public short LeftMotorSpeed; + public short RightMotorSpeed; + } + + struct XInputDeviceCapabilities + { + public byte Type; + public byte SubType; + public short Flags; + public XInputGamePad GamePad; + public XInputVibration Vibration; + } + + struct XInputBatteryInformation + { + public XInputBatteryType Type; + public XInputBatteryLevel Level; + } + + static class XInput910 + { + const string dll = "XINPUT9_1_0"; + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetCapabilities( + XInputUserIndex dwUserIndex, + XInputCapabilitiesFlags dwFlags, + ref XInputDeviceCapabilities pCapabilities); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetState + ( + XInputUserIndex dwUserIndex, + out XInputState pState + ); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode SetState + ( + XInputUserIndex dwUserIndex, + ref XInputVibration pVibration + ); + } + + static class XInput13 + { + const string dll = "XINPUT1_3"; + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetCapabilities( + XInputUserIndex dwUserIndex, + XInputCapabilitiesFlags dwFlags, + ref XInputDeviceCapabilities pCapabilities); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetState + ( + XInputUserIndex dwUserIndex, + out XInputState pState + ); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode SetState + ( + XInputUserIndex dwUserIndex, + ref XInputVibration pVibration + ); + } + + static class XInput14 + { + const string dll = "XINPUT1_4"; + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetCapabilities( + XInputUserIndex dwUserIndex, + XInputCapabilitiesFlags dwFlags, + ref XInputDeviceCapabilities pCapabilities); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode GetState + ( + XInputUserIndex dwUserIndex, + out XInputState pState + ); + + [SuppressUnmanagedCodeSecurity] + [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] + public static extern XInputErrorCode SetState + ( + XInputUserIndex dwUserIndex, + ref XInputVibration pVibration + ); + } + + #endregion + } +} From 7e5307bd4aa5cfd3c0ab3ac3f1460270354bc86a Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 03:16:32 +0100 Subject: [PATCH 100/154] Added IJoystickDevice2 interface --- Source/OpenTK/Input/GamePadCapabilities.cs | 33 -------- Source/OpenTK/Input/GamePadType.cs | 4 +- Source/OpenTK/Input/IInputDriver2.cs | 1 + Source/OpenTK/Input/IJoystickDriver2.cs | 41 ++++++++++ Source/OpenTK/Input/Joystick.cs | 51 ++++++++++++ Source/OpenTK/Input/JoystickAxis.cs | 62 +++++++++++++++ Source/OpenTK/Input/JoystickButton.cs | 78 ++++++++++++++++++ Source/OpenTK/Input/JoystickCapabilities.cs | 75 ++++++++++++++++++ Source/OpenTK/Input/JoystickDevice.cs | 74 ----------------- Source/OpenTK/Input/JoystickState.cs | 79 +++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 6 ++ Source/OpenTK/Platform/Factory.cs | 10 +++ Source/OpenTK/Platform/IPlatformFactory.cs | 2 + Source/OpenTK/Platform/MacOS/CarbonInput.cs | 5 ++ Source/OpenTK/Platform/MacOS/HIDInput.cs | 20 ++++- Source/OpenTK/Platform/MacOS/MacOSFactory.cs | 5 ++ Source/OpenTK/Platform/SDL2/Sdl2Factory.cs | 5 ++ .../OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 8 ++ .../Platform/SDL2/Sdl2JoystickDriver.cs | 16 +++- Source/OpenTK/Platform/Windows/WinFactory.cs | 7 +- .../OpenTK/Platform/Windows/WinInputBase.cs | 2 + .../OpenTK/Platform/Windows/WinMMJoystick.cs | 8 +- Source/OpenTK/Platform/Windows/WinRawInput.cs | 5 ++ .../OpenTK/Platform/Windows/XInputJoystick.cs | 4 +- Source/OpenTK/Platform/X11/X11Factory.cs | 6 ++ Source/OpenTK/Platform/X11/X11Joystick.cs | 16 +++- 26 files changed, 503 insertions(+), 120 deletions(-) create mode 100644 Source/OpenTK/Input/IJoystickDriver2.cs create mode 100644 Source/OpenTK/Input/Joystick.cs create mode 100644 Source/OpenTK/Input/JoystickAxis.cs create mode 100644 Source/OpenTK/Input/JoystickButton.cs create mode 100644 Source/OpenTK/Input/JoystickCapabilities.cs create mode 100644 Source/OpenTK/Input/JoystickState.cs diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 16707aba..c637f771 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -34,11 +34,6 @@ namespace OpenTK.Input public struct GamePadCapabilities : IEquatable { - byte axis_count; - byte button_count; - byte dpad_count; - byte trackball_count; - Buttons buttons; byte gamepad_type; bool is_connected; @@ -221,34 +216,6 @@ namespace OpenTK.Input #endregion - #region Internal Members - - internal int AxisCount - { - get { return axis_count; } - set { axis_count = (byte)value; } - } - - internal int ButtonCount - { - get { return button_count; } - set { button_count = (byte)value; } - } - - internal int DPadCount - { - get { return dpad_count; } - set { dpad_count = (byte)value; } - } - - internal int TrackballCount - { - get { return trackball_count; } - set { trackball_count = (byte)value; } - } - - #endregion - #region IEquatable Members public bool Equals(GamePadCapabilities other) diff --git a/Source/OpenTK/Input/GamePadType.cs b/Source/OpenTK/Input/GamePadType.cs index a4eddef8..1524e024 100644 --- a/Source/OpenTK/Input/GamePadType.cs +++ b/Source/OpenTK/Input/GamePadType.cs @@ -1,4 +1,4 @@ -// #region License +#region License // // GamePadType.cs // @@ -25,7 +25,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // -// #endregion +#endregion namespace OpenTK.Input { diff --git a/Source/OpenTK/Input/IInputDriver2.cs b/Source/OpenTK/Input/IInputDriver2.cs index 7cd788aa..0e4c5132 100644 --- a/Source/OpenTK/Input/IInputDriver2.cs +++ b/Source/OpenTK/Input/IInputDriver2.cs @@ -37,5 +37,6 @@ namespace OpenTK.Input IMouseDriver2 MouseDriver { get; } IKeyboardDriver2 KeyboardDriver { get; } IGamePadDriver GamePadDriver { get; } + IJoystickDriver2 JoystickDriver { get; } } } diff --git a/Source/OpenTK/Input/IJoystickDriver2.cs b/Source/OpenTK/Input/IJoystickDriver2.cs new file mode 100644 index 00000000..1359d1de --- /dev/null +++ b/Source/OpenTK/Input/IJoystickDriver2.cs @@ -0,0 +1,41 @@ +#region License +// +// IJoystickDriver2.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + interface IJoystickDriver2 + { + JoystickState GetState(int index); + JoystickCapabilities GetCapabilities(int index); + } +} diff --git a/Source/OpenTK/Input/Joystick.cs b/Source/OpenTK/Input/Joystick.cs new file mode 100644 index 00000000..0458abed --- /dev/null +++ b/Source/OpenTK/Input/Joystick.cs @@ -0,0 +1,51 @@ +#region License +// +// Joystick.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + public class Joystick + { + static readonly IJoystickDriver2 implementation = + Platform.Factory.Default.CreateJoystickDriver(); + + public static JoystickCapabilities GetCapabilities(int index) + { + return implementation.GetCapabilities(index); + } + + public static JoystickState GetState(int index) + { + return implementation.GetState(index); + } + } +} diff --git a/Source/OpenTK/Input/JoystickAxis.cs b/Source/OpenTK/Input/JoystickAxis.cs new file mode 100644 index 00000000..1e166e66 --- /dev/null +++ b/Source/OpenTK/Input/JoystickAxis.cs @@ -0,0 +1,62 @@ +#region License +// +// JoystickAxis.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + /// + /// Defines available JoystickDevice axes. + /// + public enum JoystickAxis + { + /// The first axis of the JoystickDevice. + Axis0 = 0, + /// The second axis of the JoystickDevice. + Axis1, + /// The third axis of the JoystickDevice. + Axis2, + /// The fourth axis of the JoystickDevice. + Axis3, + /// The fifth axis of the JoystickDevice. + Axis4, + /// The sixth axis of the JoystickDevice. + Axis5, + /// The seventh axis of the JoystickDevice. + Axis6, + /// The eighth axis of the JoystickDevice. + Axis7, + /// The ninth axis of the JoystickDevice. + Axis8, + /// The tenth axis of the JoystickDevice. + Axis9, + } +} diff --git a/Source/OpenTK/Input/JoystickButton.cs b/Source/OpenTK/Input/JoystickButton.cs new file mode 100644 index 00000000..cf3a9ca6 --- /dev/null +++ b/Source/OpenTK/Input/JoystickButton.cs @@ -0,0 +1,78 @@ +#region License +// +// JoystickButton.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + #region JoystickButton + + /// + /// Defines available JoystickDevice buttons. + /// + public enum JoystickButton + { + /// The first button of the JoystickDevice. + Button0 = 0, + /// The second button of the JoystickDevice. + Button1, + /// The third button of the JoystickDevice. + Button2, + /// The fourth button of the JoystickDevice. + Button3, + /// The fifth button of the JoystickDevice. + Button4, + /// The sixth button of the JoystickDevice. + Button5, + /// The seventh button of the JoystickDevice. + Button6, + /// The eighth button of the JoystickDevice. + Button7, + /// The ninth button of the JoystickDevice. + Button8, + /// The tenth button of the JoystickDevice. + Button9, + /// The eleventh button of the JoystickDevice. + Button10, + /// The twelfth button of the JoystickDevice. + Button11, + /// The thirteenth button of the JoystickDevice. + Button12, + /// The fourteenth button of the JoystickDevice. + Button13, + /// The fifteenth button of the JoystickDevice. + Button14, + /// The sixteenth button of the JoystickDevice. + Button15, + } + + #endregion +} diff --git a/Source/OpenTK/Input/JoystickCapabilities.cs b/Source/OpenTK/Input/JoystickCapabilities.cs new file mode 100644 index 00000000..5265d209 --- /dev/null +++ b/Source/OpenTK/Input/JoystickCapabilities.cs @@ -0,0 +1,75 @@ +#region License +// +// JoystickCapabilities.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + public struct JoystickCapabilities + { + byte axis_count; + byte button_count; + byte dpad_count; + byte trackball_count; + + #region Public Members + + public int AxisCount + { + get { return axis_count; } + set { axis_count = (byte)value; } + } + + public int ButtonCount + { + get { return button_count; } + set { button_count = (byte)value; } + } + + #endregion + + #region Private Members + + int DPadCount + { + get { return dpad_count; } + set { dpad_count = (byte)value; } + } + + int TrackballCount + { + get { return trackball_count; } + set { trackball_count = (byte)value; } + } + + #endregion + } +} diff --git a/Source/OpenTK/Input/JoystickDevice.cs b/Source/OpenTK/Input/JoystickDevice.cs index 6f99cdac..d02d5b4c 100644 --- a/Source/OpenTK/Input/JoystickDevice.cs +++ b/Source/OpenTK/Input/JoystickDevice.cs @@ -271,49 +271,6 @@ namespace OpenTK.Input #endregion - #region JoystickButton - - /// - /// Defines available JoystickDevice buttons. - /// - public enum JoystickButton - { - /// The first button of the JoystickDevice. - Button0 = 0, - /// The second button of the JoystickDevice. - Button1, - /// The third button of the JoystickDevice. - Button2, - /// The fourth button of the JoystickDevice. - Button3, - /// The fifth button of the JoystickDevice. - Button4, - /// The sixth button of the JoystickDevice. - Button5, - /// The seventh button of the JoystickDevice. - Button6, - /// The eighth button of the JoystickDevice. - Button7, - /// The ninth button of the JoystickDevice. - Button8, - /// The tenth button of the JoystickDevice. - Button9, - /// The eleventh button of the JoystickDevice. - Button10, - /// The twelfth button of the JoystickDevice. - Button11, - /// The thirteenth button of the JoystickDevice. - Button12, - /// The fourteenth button of the JoystickDevice. - Button13, - /// The fifteenth button of the JoystickDevice. - Button14, - /// The sixteenth button of the JoystickDevice. - Button15, - } - - #endregion - #region JoystickButtonCollection /// @@ -376,37 +333,6 @@ namespace OpenTK.Input #endregion - #region JoystickAxis - - /// - /// Defines available JoystickDevice axes. - /// - public enum JoystickAxis - { - /// The first axis of the JoystickDevice. - Axis0 = 0, - /// The second axis of the JoystickDevice. - Axis1, - /// The third axis of the JoystickDevice. - Axis2, - /// The fourth axis of the JoystickDevice. - Axis3, - /// The fifth axis of the JoystickDevice. - Axis4, - /// The sixth axis of the JoystickDevice. - Axis5, - /// The seventh axis of the JoystickDevice. - Axis6, - /// The eighth axis of the JoystickDevice. - Axis7, - /// The ninth axis of the JoystickDevice. - Axis8, - /// The tenth axis of the JoystickDevice. - Axis9, - } - - #endregion - #region JoystickAxisCollection /// diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs new file mode 100644 index 00000000..28775e69 --- /dev/null +++ b/Source/OpenTK/Input/JoystickState.cs @@ -0,0 +1,79 @@ +#region License +// +// JoystickState.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Diagnostics; +using System.Text; + +namespace OpenTK.Input +{ + public struct JoystickState + { + const int MaxAxes = 10; // JoystickAxis defines 10 axes + const float ConversionFactor = 1.0f / short.MaxValue; + unsafe fixed short axes[MaxAxes]; + JoystickButton buttons; + + public float GetAxis(JoystickAxis axis) + { + return GetAxis((int)axis); + } + + public float GetAxis(int axis) + { + float value = 0.0f; + if (axis >= 0 && axis < MaxAxes) + { + unsafe + { + fixed (short* paxis = axes) + { + value = *(paxis + axis) * ConversionFactor; + } + } + } + else + { + Debug.Print("[Joystick] Invalid axis {0}", axis); + } + return value; + } + + public bool IsButtonDown(JoystickButton button) + { + return (buttons & button) != 0; + } + + public bool IsButtonUp(JoystickButton button) + { + return (buttons & button) == 0; + } + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index c7de48e4..01e5c793 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -138,8 +138,14 @@ + + + + + + diff --git a/Source/OpenTK/Platform/Factory.cs b/Source/OpenTK/Platform/Factory.cs index a3ffa951..e49eb36b 100644 --- a/Source/OpenTK/Platform/Factory.cs +++ b/Source/OpenTK/Platform/Factory.cs @@ -149,6 +149,11 @@ namespace OpenTK.Platform return default_implementation.CreateGamePadDriver(); } + public Input.IJoystickDriver2 CreateJoystickDriver() + { + return default_implementation.CreateJoystickDriver(); + } + class UnsupportedPlatform : IPlatformFactory { #region Fields @@ -210,6 +215,11 @@ namespace OpenTK.Platform throw new PlatformNotSupportedException(error_string); } + public Input.IJoystickDriver2 CreateJoystickDriver() + { + throw new PlatformNotSupportedException(error_string); + } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/IPlatformFactory.cs b/Source/OpenTK/Platform/IPlatformFactory.cs index 541c8710..c59654f3 100644 --- a/Source/OpenTK/Platform/IPlatformFactory.cs +++ b/Source/OpenTK/Platform/IPlatformFactory.cs @@ -52,5 +52,7 @@ namespace OpenTK.Platform OpenTK.Input.IMouseDriver2 CreateMouseDriver(); OpenTK.Input.IGamePadDriver CreateGamePadDriver(); + + Input.IJoystickDriver2 CreateJoystickDriver(); } } diff --git a/Source/OpenTK/Platform/MacOS/CarbonInput.cs b/Source/OpenTK/Platform/MacOS/CarbonInput.cs index 1fd65a2c..640b99b8 100644 --- a/Source/OpenTK/Platform/MacOS/CarbonInput.cs +++ b/Source/OpenTK/Platform/MacOS/CarbonInput.cs @@ -113,5 +113,10 @@ namespace OpenTK.Platform.MacOS throw new NotImplementedException(); } } + + public IJoystickDriver2 JoystickDriver + { + get { throw new NotImplementedException(); } + } } } diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index c3e55612..613d1c64 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -50,7 +50,7 @@ namespace OpenTK.Platform.MacOS // Requires Mac OS X 10.5 or higher. // Todo: create a driver for older installations. Maybe use CGGetLastMouseDelta for that? - class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IGamePadDriver + class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IGamePadDriver, IJoystickDriver2 { #region Fields @@ -93,7 +93,7 @@ namespace OpenTK.Platform.MacOS #endregion - #region Private Members + #region Private Members IOHIDManagerRef CreateHIDManager() { @@ -292,6 +292,8 @@ namespace OpenTK.Platform.MacOS public IMouseDriver2 MouseDriver { get { return this; } } public IKeyboardDriver2 KeyboardDriver { get { return this; } } public IGamePadDriver GamePadDriver { get { return this; } } + public IJoystickDriver2 JoystickDriver { get { return this; } } + #endregion @@ -385,6 +387,20 @@ namespace OpenTK.Platform.MacOS #endregion + #region IJoystickDriver2 Members + + JoystickState IJoystickDriver2.GetState(int index) + { + throw new NotImplementedException(); + } + + JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) + { + throw new NotImplementedException(); + } + + #endregion + #region NativeMethods class NativeMethods diff --git a/Source/OpenTK/Platform/MacOS/MacOSFactory.cs b/Source/OpenTK/Platform/MacOS/MacOSFactory.cs index ad540311..e7dd5f05 100644 --- a/Source/OpenTK/Platform/MacOS/MacOSFactory.cs +++ b/Source/OpenTK/Platform/MacOS/MacOSFactory.cs @@ -93,6 +93,11 @@ namespace OpenTK.Platform.MacOS { return InputDriver.GamePadDriver; } + + public IJoystickDriver2 CreateJoystickDriver() + { + return InputDriver.JoystickDriver; + } #endregion diff --git a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs index 4c39156f..b8015f6b 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2Factory.cs @@ -104,6 +104,11 @@ namespace OpenTK.Platform.SDL2 return InputDriver.GamePadDriver; } + public IJoystickDriver2 CreateJoystickDriver() + { + return InputDriver.JoystickDriver; + } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index 3a69be40..023af9a2 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -220,6 +220,14 @@ namespace OpenTK.Platform.SDL2 } } + public IJoystickDriver2 JoystickDriver + { + get + { + return joystick_driver; + } + } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 6c7e2728..701c38d6 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -32,7 +32,7 @@ using OpenTK.Input; namespace OpenTK.Platform.SDL2 { - class Sdl2JoystickDriver : IJoystickDriver, IGamePadDriver, IDisposable + class Sdl2JoystickDriver : IJoystickDriver, IJoystickDriver2, IGamePadDriver, IDisposable { const float RangeMultiplier = 1.0f / 32768.0f; @@ -322,6 +322,20 @@ namespace OpenTK.Platform.SDL2 #endregion + #region IJoystickDriver2 Members + + JoystickState IJoystickDriver2.GetState(int index) + { + throw new NotImplementedException(); + } + + JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) + { + throw new NotImplementedException(); + } + + #endregion + #region IDisposable Members void Dispose(bool manual) diff --git a/Source/OpenTK/Platform/Windows/WinFactory.cs b/Source/OpenTK/Platform/Windows/WinFactory.cs index 5ea1a8eb..4fa46e2e 100644 --- a/Source/OpenTK/Platform/Windows/WinFactory.cs +++ b/Source/OpenTK/Platform/Windows/WinFactory.cs @@ -130,7 +130,12 @@ namespace OpenTK.Platform.Windows { return InputDriver.GamePadDriver; } - + + public IJoystickDriver2 CreateJoystickDriver() + { + return InputDriver.JoystickDriver; + } + #endregion IInputDriver2 InputDriver diff --git a/Source/OpenTK/Platform/Windows/WinInputBase.cs b/Source/OpenTK/Platform/Windows/WinInputBase.cs index 252a6f8d..7d0865f1 100644 --- a/Source/OpenTK/Platform/Windows/WinInputBase.cs +++ b/Source/OpenTK/Platform/Windows/WinInputBase.cs @@ -164,6 +164,8 @@ namespace OpenTK.Platform.Windows public abstract IKeyboardDriver2 KeyboardDriver { get; } public abstract IGamePadDriver GamePadDriver { get; } + public abstract IJoystickDriver2 JoystickDriver { get; } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 07c208cc..e7c71541 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -445,10 +445,10 @@ namespace OpenTK.Platform.Windows JoystickError result = UnsafeNativeMethods.joyGetDevCaps(index, out caps, JoyCaps.SizeInBytes); if (result == JoystickError.NoError) { - gpcaps.AxisCount = caps.NumAxes; - gpcaps.ButtonCount = caps.NumButtons; - if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) - gpcaps.DPadCount++; + //gpcaps.AxisCount = caps.NumAxes; + //gpcaps.ButtonCount = caps.NumButtons; + //if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) + // gpcaps.DPadCount++; } } else diff --git a/Source/OpenTK/Platform/Windows/WinRawInput.cs b/Source/OpenTK/Platform/Windows/WinRawInput.cs index c905b65b..04025efd 100644 --- a/Source/OpenTK/Platform/Windows/WinRawInput.cs +++ b/Source/OpenTK/Platform/Windows/WinRawInput.cs @@ -190,6 +190,11 @@ namespace OpenTK.Platform.Windows get { return joystick_driver; } } + public override IJoystickDriver2 JoystickDriver + { + get { throw new NotImplementedException(); } + } + #endregion } } diff --git a/Source/OpenTK/Platform/Windows/XInputJoystick.cs b/Source/OpenTK/Platform/Windows/XInputJoystick.cs index f3e0c04e..c6d7def1 100644 --- a/Source/OpenTK/Platform/Windows/XInputJoystick.cs +++ b/Source/OpenTK/Platform/Windows/XInputJoystick.cs @@ -1,4 +1,4 @@ -// #region License +#region License // // XInputJoystick.cs // @@ -25,7 +25,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // -// #endregion +#endregion using System; using System.Collections.Generic; diff --git a/Source/OpenTK/Platform/X11/X11Factory.cs b/Source/OpenTK/Platform/X11/X11Factory.cs index 8b8344df..0fb80058 100644 --- a/Source/OpenTK/Platform/X11/X11Factory.cs +++ b/Source/OpenTK/Platform/X11/X11Factory.cs @@ -98,6 +98,12 @@ namespace OpenTK.Platform.X11 return new X11Joystick(); } + public virtual OpenTK.Input.IJoystickDriver2 CreateJoystickDriver() + { + return new X11Joystick(); + } + + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs index b4948169..36fac9f2 100644 --- a/Source/OpenTK/Platform/X11/X11Joystick.cs +++ b/Source/OpenTK/Platform/X11/X11Joystick.cs @@ -36,7 +36,7 @@ namespace OpenTK.Platform.X11 { struct X11JoyDetails { } - sealed class X11Joystick : IJoystickDriver, IGamePadDriver + sealed class X11Joystick : IJoystickDriver, IJoystickDriver2, IGamePadDriver { #region Fields @@ -277,5 +277,19 @@ namespace OpenTK.Platform.X11 } #endregion + + #region IJoystickDriver2 Members + + JoystickState IJoystickDriver2.GetState(int index) + { + throw new NotImplementedException(); + } + + JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) + { + throw new NotImplementedException(); + } + + #endregion } } From 2839db587e408e14fe47a974e25609bf2073cb07 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 12:47:09 +0100 Subject: [PATCH 101/154] Implemented thumbsticks and trigger caps --- .../Input/{GamePadAxis.cs => GamePadAxes.cs} | 13 +- Source/OpenTK/Input/GamePadCapabilities.cs | 23 +- Source/OpenTK/Input/GamePadState.cs | 23 +- Source/OpenTK/Input/GamePadType.cs | 2 + .../Platform/SDL2/Sdl2JoystickDriver.cs | 2 +- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 8 +- .../OpenTK/Platform/Windows/XInputJoystick.cs | 267 ++++++++++++------ 7 files changed, 230 insertions(+), 108 deletions(-) rename Source/OpenTK/Input/{GamePadAxis.cs => GamePadAxes.cs} (85%) diff --git a/Source/OpenTK/Input/GamePadAxis.cs b/Source/OpenTK/Input/GamePadAxes.cs similarity index 85% rename from Source/OpenTK/Input/GamePadAxis.cs rename to Source/OpenTK/Input/GamePadAxes.cs index f619ab6a..3ddea306 100644 --- a/Source/OpenTK/Input/GamePadAxis.cs +++ b/Source/OpenTK/Input/GamePadAxes.cs @@ -27,12 +27,15 @@ using System; namespace OpenTK.Input { - internal enum GamePadAxis + [Flags] + internal enum GamePadAxes : byte { - LeftX, - LeftY, - RightX, - RightY + LeftX = 1 << 0, + LeftY = 1 << 1, + LeftTrigger = 1 << 2, + RightX = 1 << 3, + RightY = 1 << 4, + RightTrigger = 1 << 5, } } diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index c637f771..2db7b612 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -35,15 +35,17 @@ namespace OpenTK.Input public struct GamePadCapabilities : IEquatable { Buttons buttons; + GamePadAxes axes; byte gamepad_type; bool is_connected; #region Constructors - public GamePadCapabilities(GamePadType type, Buttons buttons, bool is_connected) + internal GamePadCapabilities(GamePadType type, GamePadAxes axes, Buttons buttons, bool is_connected) : this() { gamepad_type = (byte)type; + this.axes = axes; this.buttons = buttons; this.is_connected = is_connected; } @@ -134,32 +136,32 @@ namespace OpenTK.Input public bool HasLeftXThumbStick { - get { return false; } + get { return (axes & GamePadAxes.LeftX) != 0; } } public bool HasLeftYThumbStick { - get { return false; } + get { return (axes & GamePadAxes.LeftY) != 0; } } public bool HasRightXThumbStick { - get { return false; } + get { return (axes & GamePadAxes.RightX) != 0; } } public bool HasRightYThumbStick { - get { return false; } + get { return (axes & GamePadAxes.RightY) != 0; } } public bool HasLeftTrigger { - get { return false; } + get { return (axes & GamePadAxes.LeftTrigger) != 0; } } public bool HasRightTrigger { - get { return false; } + get { return (axes & GamePadAxes.RightTrigger) != 0; } } public bool HasLeftVibrationMotor @@ -195,8 +197,11 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Type: {0}; Buttons: {1}; Connected: {2}}}", - GamePadType, Convert.ToString((int)buttons, 2), IsConnected); + "{{Type: {0}; Axes: {1}; Buttons: {2}; Connected: {3}}}", + GamePadType, + Convert.ToString((int)axes, 2), + Convert.ToString((int)buttons, 2), + IsConnected); } public override int GetHashCode() diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index 22111b53..bd196982 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -62,6 +62,11 @@ namespace OpenTK.Input get { return new GamePadDPad(buttons); } } + public GamePadTriggers Triggers + { + get { return new GamePadTriggers(left_trigger, right_trigger); } + } + public bool IsConnected { get { return is_connected; } @@ -104,23 +109,23 @@ namespace OpenTK.Input #region Internal Members - internal void SetAxis(GamePadAxis axis, short value) + internal void SetAxis(GamePadAxes axis, short value) { switch (axis) { - case GamePadAxis.LeftX: + case GamePadAxes.LeftX: left_stick_x = value; break; - case GamePadAxis.LeftY: + case GamePadAxes.LeftY: left_stick_y = value; break; - case GamePadAxis.RightX: + case GamePadAxes.RightX: right_stick_x = value; break; - case GamePadAxis.RightY: + case GamePadAxes.RightY: right_stick_y = value; break; @@ -146,11 +151,17 @@ namespace OpenTK.Input is_connected = connected; } + internal void SetTriggers(byte left, byte right) + { + left_trigger = left; + right_trigger = right; + } + #endregion #region Private Members - bool IsAxisValid(GamePadAxis axis) + bool IsAxisValid(GamePadAxes axis) { int index = (int)axis; return index >= 0 && index < GamePad.MaxAxisCount; diff --git a/Source/OpenTK/Input/GamePadType.cs b/Source/OpenTK/Input/GamePadType.cs index 1524e024..37311627 100644 --- a/Source/OpenTK/Input/GamePadType.cs +++ b/Source/OpenTK/Input/GamePadType.cs @@ -41,5 +41,7 @@ namespace OpenTK.Input BigButtonPad, DrumKit, GamePad, + ArcadePad, + BassGuitar, } } diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 701c38d6..d5caa2c1 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -258,7 +258,7 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsControllerValid(id)) { - controllers[id].State.SetAxis((GamePadAxis)ev.Axis, ev.Value); + controllers[id].State.SetAxis((GamePadAxes)ev.Axis, ev.Value); } else { diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index e7c71541..1821b136 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -470,10 +470,10 @@ namespace OpenTK.Platform.Windows info.Flags = JoystickFlags.All; UnsafeNativeMethods.joyGetPosEx(index, ref info); - state.SetAxis(GamePadAxis.LeftX, (short)info.XPos); - state.SetAxis(GamePadAxis.LeftY, (short)info.YPos); - state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); - state.SetAxis(GamePadAxis.RightY, (short)info.RPos); + state.SetAxis(GamePadAxes.LeftX, (short)info.XPos); + state.SetAxis(GamePadAxes.LeftY, (short)info.YPos); + state.SetAxis(GamePadAxes.RightX, (short)info.ZPos); + state.SetAxis(GamePadAxes.RightY, (short)info.RPos); //state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); //state.SetAxis(GamePadAxis.RightY, (short)info.RPos); diff --git a/Source/OpenTK/Platform/Windows/XInputJoystick.cs b/Source/OpenTK/Platform/Windows/XInputJoystick.cs index c6d7def1..23710df0 100644 --- a/Source/OpenTK/Platform/Windows/XInputJoystick.cs +++ b/Source/OpenTK/Platform/Windows/XInputJoystick.cs @@ -33,41 +33,56 @@ using System.Text; using OpenTK.Input; using System.Runtime.InteropServices; using System.Security; +using System.Diagnostics; namespace OpenTK.Platform.Windows { - class XInputJoystick : IGamePadDriver + class XInputJoystick : IGamePadDriver, IDisposable { + XInput xinput = new XInput(); + #region IGamePadDriver Members public GamePadState GetState(int index) { XInputState xstate; - XInput910.GetState((XInputUserIndex)index, out xstate); + XInputErrorCode error = xinput.GetState((XInputUserIndex)index, out xstate); GamePadState state = new GamePadState(); - state.SetButton(Buttons.A, (xstate.GamePad.Buttons & XInputButtons.A) != 0); - state.SetButton(Buttons.B, (xstate.GamePad.Buttons & XInputButtons.B) != 0); - state.SetButton(Buttons.X, (xstate.GamePad.Buttons & XInputButtons.X) != 0); - state.SetButton(Buttons.Y, (xstate.GamePad.Buttons & XInputButtons.Y) != 0); - state.SetButton(Buttons.Start, (xstate.GamePad.Buttons & XInputButtons.Start) != 0); - state.SetButton(Buttons.Back, (xstate.GamePad.Buttons & XInputButtons.Back) != 0); - //state.SetButton(Buttons.BigButton, (xstate.GamePad.Buttons & XInputButtons.???) != 0); - state.SetButton(Buttons.LeftShoulder, (xstate.GamePad.Buttons & XInputButtons.LeftShoulder) != 0); - state.SetButton(Buttons.RightShoulder, (xstate.GamePad.Buttons & XInputButtons.RightShoulder) != 0); - state.SetButton(Buttons.LeftStick, (xstate.GamePad.Buttons & XInputButtons.LeftThumb) != 0); - state.SetButton(Buttons.RightStick, (xstate.GamePad.Buttons & XInputButtons.RightThumb) != 0); - state.SetButton(Buttons.DPadDown, (xstate.GamePad.Buttons & XInputButtons.DPadDown) != 0); - state.SetButton(Buttons.DPadUp, (xstate.GamePad.Buttons & XInputButtons.DPadUp) != 0); - state.SetButton(Buttons.DPadLeft, (xstate.GamePad.Buttons & XInputButtons.DPadLeft) != 0); - state.SetButton(Buttons.DPadRight, (xstate.GamePad.Buttons & XInputButtons.DPadRight) != 0); + if (error == XInputErrorCode.Success) + { + state.SetConnected(true); + + state.SetAxis(GamePadAxes.LeftX, xstate.GamePad.ThumbLX); + state.SetAxis(GamePadAxes.LeftY, xstate.GamePad.ThumbLY); + state.SetAxis(GamePadAxes.RightX, xstate.GamePad.ThumbRX); + state.SetAxis(GamePadAxes.RightY, xstate.GamePad.ThumbRY); + + state.SetTriggers(xstate.GamePad.LeftTrigger, xstate.GamePad.RightTrigger); + + state.SetButton(TranslateButtons(xstate.GamePad.Buttons), true); + } return state; } public GamePadCapabilities GetCapabilities(int index) { - throw new NotImplementedException(); + XInputDeviceCapabilities xcaps; + XInputErrorCode error = xinput.GetCapabilities( + (XInputUserIndex)index, + XInputCapabilitiesFlags.Default, + out xcaps); + + if (error == XInputErrorCode.Success) + { + GamePadType type = TranslateSubType(xcaps.SubType); + Buttons buttons = TranslateButtons(xcaps.GamePad.Buttons); + GamePadAxes axes = TranslateAxes(ref xcaps.GamePad); + + return new GamePadCapabilities(type, axes, buttons, true); + } + return new GamePadCapabilities(); } public string GetName(int index) @@ -78,6 +93,58 @@ namespace OpenTK.Platform.Windows #endregion #region Private Members + GamePadAxes TranslateAxes(ref XInputGamePad pad) + { + GamePadAxes axes = 0; + axes |= pad.ThumbLX != 0 ? GamePadAxes.LeftX : 0; + axes |= pad.ThumbLY != 0 ? GamePadAxes.LeftY : 0; + axes |= pad.LeftTrigger != 0 ? GamePadAxes.LeftTrigger : 0; + axes |= pad.ThumbRX != 0 ? GamePadAxes.RightX : 0; + axes |= pad.ThumbRY != 0 ? GamePadAxes.RightY : 0; + axes |= pad.RightTrigger != 0 ? GamePadAxes.RightTrigger : 0; + return axes; + } + + Buttons TranslateButtons(XInputButtons xbuttons) + { + Buttons buttons = 0; + buttons |= (xbuttons & XInputButtons.A) != 0 ? Buttons.A : 0; + buttons |= (xbuttons & XInputButtons.B) != 0 ? Buttons.B : 0; + buttons |= (xbuttons & XInputButtons.X) != 0 ? Buttons.X : 0; + buttons |= (xbuttons & XInputButtons.Y) != 0 ? Buttons.Y : 0; + buttons |= (xbuttons & XInputButtons.Start) != 0 ? Buttons.Start : 0; + buttons |= (xbuttons & XInputButtons.Back) != 0 ? Buttons.Back : 0; + //buttons |= (xbuttons & XInputButtons.BigButton) != 0 ? Buttons.BigButton : 0; + buttons |= (xbuttons & XInputButtons.LeftShoulder) != 0 ? Buttons.LeftShoulder : 0; + buttons |= (xbuttons & XInputButtons.RightShoulder) != 0 ? Buttons.RightShoulder : 0; + buttons |= (xbuttons & XInputButtons.LeftThumb) != 0 ? Buttons.LeftStick : 0; + buttons |= (xbuttons & XInputButtons.RightThumb) != 0 ? Buttons.RightStick : 0; + buttons |= (xbuttons & XInputButtons.DPadDown) != 0 ? Buttons.DPadDown : 0; + buttons |= (xbuttons & XInputButtons.DPadUp) != 0 ? Buttons.DPadUp : 0; + buttons |= (xbuttons & XInputButtons.DPadLeft) != 0 ? Buttons.DPadLeft : 0; + buttons |= (xbuttons & XInputButtons.DPadRight) != 0 ? Buttons.DPadRight : 0; + return buttons; + } + + GamePadType TranslateSubType(XInputDeviceSubType xtype) + { + switch (xtype) + { + case XInputDeviceSubType.ArcadePad: return GamePadType.ArcadePad; + case XInputDeviceSubType.ArcadeStick: return GamePadType.ArcadeStick; + case XInputDeviceSubType.DancePad: return GamePadType.DancePad; + case XInputDeviceSubType.DrumKit: return GamePadType.DrumKit; + case XInputDeviceSubType.FlightStick: return GamePadType.FlightStick; + case XInputDeviceSubType.GamePad: return GamePadType.GamePad; + case XInputDeviceSubType.Guitar: return GamePadType.Guitar; + case XInputDeviceSubType.GuitarAlternate: return GamePadType.AlternateGuitar; + case XInputDeviceSubType.GuitarBass: return GamePadType.BassGuitar; + case XInputDeviceSubType.Wheel: return GamePadType.Wheel; + case XInputDeviceSubType.Unknown: + default: + return GamePadType.Unknown; + } + } enum XInputErrorCode { @@ -85,12 +152,12 @@ namespace OpenTK.Platform.Windows DeviceNotConnected } - enum XInputType + enum XInputDeviceType : byte { GamePad } - enum XInputSubType + enum XInputDeviceSubType : byte { Unknown = 0, GamePad = 1, @@ -107,10 +174,10 @@ namespace OpenTK.Platform.Windows enum XInputCapabilities { - Ffb = 0x0001, + ForceFeedback = 0x0001, Wireless = 0x0002, Voice = 0x0004, - Pmd = 0x0008, + PluginModules = 0x0008, NoNavigation = 0x0010, } @@ -197,8 +264,8 @@ namespace OpenTK.Platform.Windows struct XInputDeviceCapabilities { - public byte Type; - public byte SubType; + public XInputDeviceType Type; + public XInputDeviceSubType SubType; public short Flags; public XInputGamePad GamePad; public XInputVibration Vibration; @@ -210,90 +277,124 @@ namespace OpenTK.Platform.Windows public XInputBatteryLevel Level; } - static class XInput910 + class XInput : IDisposable { - const string dll = "XINPUT9_1_0"; + IntPtr dll; + + internal XInput() + { + // Try to load the newest XInput***.dll installed on the system + // The delegates below will be loaded dynamically from that dll + dll = Functions.LoadLibrary("XINPUT1_4"); + if (dll == IntPtr.Zero) + dll = Functions.LoadLibrary("XINPUT1_3"); + if (dll == IntPtr.Zero) + dll = Functions.LoadLibrary("XINPUT1_2"); + if (dll == IntPtr.Zero) + dll = Functions.LoadLibrary("XINPUT1_1"); + if (dll == IntPtr.Zero) + dll = Functions.LoadLibrary("XINPUT9_1_0"); + if (dll == IntPtr.Zero) + throw new NotSupportedException("XInput was not found on this platform"); + + // Load the entry points we are interested in from that dll + GetCapabilities = (XInputGetCapabilities)Load("XInputGetCapabilities", typeof(XInputGetCapabilities)); + GetState = (XInputGetState)Load("XInputGetState", typeof(XInputGetState)); + SetState = (XInputSetState)Load("XInputSetState", typeof(XInputSetState)); + } + + #region Private Members + + Delegate Load(string name, Type type) + { + IntPtr pfunc = Functions.GetProcAddress(dll, name); + if (pfunc != IntPtr.Zero) + return Marshal.GetDelegateForFunctionPointer(pfunc, type); + return null; + } + + #endregion + + #region Internal Members + + internal XInputGetCapabilities GetCapabilities; + internal XInputGetState GetState; + internal XInputSetState SetState; [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetCapabilities( + internal delegate XInputErrorCode XInputGetCapabilities( XInputUserIndex dwUserIndex, XInputCapabilitiesFlags dwFlags, - ref XInputDeviceCapabilities pCapabilities); + out XInputDeviceCapabilities pCapabilities); [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetState + internal delegate XInputErrorCode XInputGetState ( XInputUserIndex dwUserIndex, out XInputState pState ); [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode SetState + internal delegate XInputErrorCode XInputSetState ( XInputUserIndex dwUserIndex, ref XInputVibration pVibration ); + + #endregion + + #region IDisposable Members + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void Dispose(bool manual) + { + if (manual) + { + if (dll != IntPtr.Zero) + { + Functions.FreeLibrary(dll); + dll = IntPtr.Zero; + } + } + } + + #endregion } - static class XInput13 + #endregion + + #region IDisposable Members + + public void Dispose() { - const string dll = "XINPUT1_3"; - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetCapabilities( - XInputUserIndex dwUserIndex, - XInputCapabilitiesFlags dwFlags, - ref XInputDeviceCapabilities pCapabilities); - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetState - ( - XInputUserIndex dwUserIndex, - out XInputState pState - ); - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode SetState - ( - XInputUserIndex dwUserIndex, - ref XInputVibration pVibration - ); + Dispose(true); + GC.SuppressFinalize(this); } - static class XInput14 + void Dispose(bool manual) { - const string dll = "XINPUT1_4"; - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetCapabilities", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetCapabilities( - XInputUserIndex dwUserIndex, - XInputCapabilitiesFlags dwFlags, - ref XInputDeviceCapabilities pCapabilities); - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputGetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode GetState - ( - XInputUserIndex dwUserIndex, - out XInputState pState - ); - - [SuppressUnmanagedCodeSecurity] - [DllImport(dll, EntryPoint = "XInputSetState", ExactSpelling = true, SetLastError = false)] - public static extern XInputErrorCode SetState - ( - XInputUserIndex dwUserIndex, - ref XInputVibration pVibration - ); + if (manual) + { + xinput.Dispose(); + } + else + { + Debug.Print("{0} leaked, did you forget to call Dispose()?", typeof(XInputJoystick).Name); + } } +#if DEBUG + ~XInputJoystick() + { + Dispose(false); + } +#endif + #endregion } } From 52daef4b0d7f3650041abfa62aae6d6688d1b2cd Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 12:48:15 +0100 Subject: [PATCH 102/154] Added internal GamePadMapping class --- Source/OpenTK/Input/GamePadMapping.cs | 39 +++++++++++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 3 ++- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 Source/OpenTK/Input/GamePadMapping.cs diff --git a/Source/OpenTK/Input/GamePadMapping.cs b/Source/OpenTK/Input/GamePadMapping.cs new file mode 100644 index 00000000..9ddca29f --- /dev/null +++ b/Source/OpenTK/Input/GamePadMapping.cs @@ -0,0 +1,39 @@ +#region License +// +// GamePadMapping.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + class GamePadMapping + { + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 01e5c793..be7ac936 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -133,6 +133,7 @@ + @@ -748,7 +749,7 @@ - + From 91b54cfbf3dcae47a1c90af2e9729c873bd2c65f Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 12:52:57 +0100 Subject: [PATCH 103/154] No reason to comment out #region License --- Source/OpenTK/Input/GamePadCapabilities.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 2db7b612..7fbe8055 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -1,4 +1,4 @@ -// #region License +#region License // // GamePadCapabilities.cs // @@ -25,7 +25,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // -// #endregion +#endregion using System; From 02fb6bf2f92da5e38332e3bef7dcbabcb87a289d Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 14:21:37 +0100 Subject: [PATCH 104/154] Implements JoystickState and Capabilities setters --- Source/OpenTK/Input/JoystickCapabilities.cs | 34 ++++++++--- Source/OpenTK/Input/JoystickState.cs | 67 +++++++++++++++++++-- 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/Source/OpenTK/Input/JoystickCapabilities.cs b/Source/OpenTK/Input/JoystickCapabilities.cs index 5265d209..b25fa69b 100644 --- a/Source/OpenTK/Input/JoystickCapabilities.cs +++ b/Source/OpenTK/Input/JoystickCapabilities.cs @@ -38,20 +38,35 @@ namespace OpenTK.Input byte axis_count; byte button_count; byte dpad_count; - byte trackball_count; + bool is_connected; + + #region Constructors + + public JoystickCapabilities(int axis_count, int button_count, bool is_connected) + { + if (axis_count < 0 || axis_count >= JoystickState.MaxAxes) + throw new ArgumentOutOfRangeException("axis_count"); + if (button_count < 0 || button_count >= JoystickState.MaxButtons) + throw new ArgumentOutOfRangeException("axis_count"); + + this.axis_count = (byte)axis_count; + this.button_count = (byte)button_count; + this.dpad_count = 0; // Todo: either remove dpad_count or add it as a parameter + this.is_connected = is_connected; + } + + #endregion #region Public Members public int AxisCount { get { return axis_count; } - set { axis_count = (byte)value; } } public int ButtonCount { get { return button_count; } - set { button_count = (byte)value; } } #endregion @@ -61,15 +76,14 @@ namespace OpenTK.Input int DPadCount { get { return dpad_count; } - set { dpad_count = (byte)value; } - } - - int TrackballCount - { - get { return trackball_count; } - set { trackball_count = (byte)value; } } #endregion + + public bool IsConnected + { + get { return is_connected; } + } + } } diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index 28775e69..8a233df6 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -36,10 +36,18 @@ namespace OpenTK.Input { public struct JoystickState { - const int MaxAxes = 10; // JoystickAxis defines 10 axes - const float ConversionFactor = 1.0f / short.MaxValue; + // If we ever add more values to JoystickAxis or JoystickButton + // then we'll need to increase these limits. + internal const int MaxAxes = 10; + internal const int MaxButtons = 32; + + const float ConversionFactor = 1.0f / (short.MaxValue + 1); + unsafe fixed short axes[MaxAxes]; - JoystickButton buttons; + int buttons; + bool is_connected; + + #region Public Members public float GetAxis(JoystickAxis axis) { @@ -66,14 +74,63 @@ namespace OpenTK.Input return value; } + public ButtonState GetButton(JoystickButton button) + { + return (buttons & (1 << (int)button)) != 0 ? ButtonState.Pressed : ButtonState.Released; + } + public bool IsButtonDown(JoystickButton button) { - return (buttons & button) != 0; + return (buttons & (1 << (int)button)) != 0; } public bool IsButtonUp(JoystickButton button) { - return (buttons & button) == 0; + return (buttons & (1 << (int)button)) == 0; } + + public bool IsConnected + { + get { return is_connected; } + } + + #endregion + + #region Internal Members + + internal void SetAxis(JoystickAxis axis, short value) + { + int index = (int)axis; + if (index < 0 || index >= MaxAxes) + throw new ArgumentOutOfRangeException("axis"); + + unsafe + { + fixed (short* paxes = axes) + { + *(paxes + index) = value; + } + } + } + + internal void SetButton(JoystickButton button, bool value) + { + int index = 1 << (int)button; + if (value) + { + buttons |= index; + } + else + { + buttons &= ~index; + } + } + + internal void SetIsConnected(bool value) + { + is_connected = value; + } + + #endregion } } From 165aa5bde62d490513d5e341d31d94e8421b0a98 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 14:22:03 +0100 Subject: [PATCH 105/154] Added MappedGamePadDriver skeleton implementation --- Source/OpenTK/OpenTK.csproj | 1 + Source/OpenTK/Platform/MappedGamePadDriver.cs | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 Source/OpenTK/Platform/MappedGamePadDriver.cs diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index be7ac936..a378e483 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -164,6 +164,7 @@ + diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs new file mode 100644 index 00000000..346be196 --- /dev/null +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -0,0 +1,83 @@ +#region License +// +// MappedGamePadDriver.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; +using OpenTK.Input; + +namespace OpenTK.Platform +{ + /// \internal + /// + /// Implements IGamePadDriver using OpenTK.Input.Joystick + /// and a gamepad-specific axis/button mapping. + /// + /// + /// + /// This class supports OpenTK and is not meant to be accessed by user code. + /// + /// + /// To support gamepads on platforms that do not offer a gamepad-optimized API, + /// we need to use the generic OpenTK.Input.Joystick and implement a custom + /// mapping scheme to provide a stable mapping to OpenTK.Input.GamePad. This + /// class implements this mapping scheme. + /// + /// + class MappedGamePadDriver : IGamePadDriver + { + public GamePadState GetState(int index) + { + JoystickState joy = Joystick.GetState(index); + GamePadState pad = new GamePadState(); + if (joy.IsConnected) + { + GamePadMapping mapping = new GamePadMapping();//GamePadMapping.Lookup() + // Todo: implement mapping + } + return pad; + } + + public GamePadCapabilities GetCapabilities(int index) + { + JoystickCapabilities joy = Joystick.GetCapabilities(index); + GamePadCapabilities pad = new GamePadCapabilities(); + if (joy.IsConnected) + { + // Todo: implement mapping + } + return pad; + } + + public string GetName(int index) + { + throw new NotImplementedException(); + } + } +} From 15c01d0d5c4249d13f6e2fe835c839daea3cbf23 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 14:24:29 +0100 Subject: [PATCH 106/154] WinMMJoystick implements IJoystickDriver2 WinMM is optimized for general joystick use, not for the canonical GamePad layout. Instead of exposing IGamePadDriver directly, it should expose IJoystickDriver2 and use a mapping driver to get GamePad support. --- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 131 ++++++++---------- 1 file changed, 59 insertions(+), 72 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 1821b136..882ce5f0 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -36,7 +36,7 @@ using System.Diagnostics; namespace OpenTK.Platform.Windows { - sealed class WinMMJoystick : IJoystickDriver, IGamePadDriver + sealed class WinMMJoystick : IJoystickDriver, IJoystickDriver2 { #region Fields @@ -242,6 +242,64 @@ namespace OpenTK.Platform.Windows #endregion + #region IJoystickDriver2 Members + + public JoystickCapabilities GetCapabilities(int index) + { + if (IsValid(index)) + { + JoyCaps mmcaps; + JoystickError result = UnsafeNativeMethods.joyGetDevCaps(index, out mmcaps, JoyCaps.SizeInBytes); + if (result == JoystickError.NoError) + { + JoystickCapabilities caps = new JoystickCapabilities( + mmcaps.NumAxes, mmcaps.NumButtons, true); + //if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) + // gpcaps.DPadCount++; + return caps; + } + } + else + { + Debug.Print("[Win] Invalid WinMM joystick device {0}", index); + } + + return new JoystickCapabilities(); + } + + public JoystickState GetState(int index) + { + JoystickState state = new JoystickState(); + + if (IsValid(index)) + { + JoyInfoEx info = new JoyInfoEx(); + info.Size = JoyInfoEx.SizeInBytes; + info.Flags = JoystickFlags.All; + UnsafeNativeMethods.joyGetPosEx(index, ref info); + + state.SetAxis(JoystickAxis.Axis0, (short)info.XPos); + state.SetAxis(JoystickAxis.Axis1, (short)info.YPos); + state.SetAxis(JoystickAxis.Axis2, (short)info.ZPos); + state.SetAxis(JoystickAxis.Axis3, (short)info.RPos); + state.SetAxis(JoystickAxis.Axis4, (short)info.ZPos); + state.SetAxis(JoystickAxis.Axis5, (short)info.RPos); + + for (int i = 0; i < 16; i++) + { + state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); + } + } + else + { + Debug.Print("[Win] Invalid WinMM joystick device {0}", index); + } + + return state; + } + + #endregion + #region IDisposable public void Dispose() @@ -432,76 +490,5 @@ namespace OpenTK.Platform.Windows } #endregion - - #region IGamePadDriver Members - - public GamePadCapabilities GetCapabilities(int index) - { - GamePadCapabilities gpcaps = new GamePadCapabilities(); - - if (IsValid(index)) - { - JoyCaps caps; - JoystickError result = UnsafeNativeMethods.joyGetDevCaps(index, out caps, JoyCaps.SizeInBytes); - if (result == JoystickError.NoError) - { - //gpcaps.AxisCount = caps.NumAxes; - //gpcaps.ButtonCount = caps.NumButtons; - //if ((caps.Capabilities & JoystCapsFlags.HasPov) != 0) - // gpcaps.DPadCount++; - } - } - else - { - Debug.Print("[Win] Invalid WinMM joystick device {0}", index); - } - - return gpcaps; - } - - public GamePadState GetState(int index) - { - GamePadState state = new GamePadState(); - - if (IsValid(index)) - { - JoyInfoEx info = new JoyInfoEx(); - info.Size = JoyInfoEx.SizeInBytes; - info.Flags = JoystickFlags.All; - UnsafeNativeMethods.joyGetPosEx(index, ref info); - - state.SetAxis(GamePadAxes.LeftX, (short)info.XPos); - state.SetAxis(GamePadAxes.LeftY, (short)info.YPos); - state.SetAxis(GamePadAxes.RightX, (short)info.ZPos); - state.SetAxis(GamePadAxes.RightY, (short)info.RPos); - //state.SetAxis(GamePadAxis.RightX, (short)info.ZPos); - //state.SetAxis(GamePadAxis.RightY, (short)info.RPos); - - state.SetButton(Buttons.A, (info.Buttons & 1 << 0) != 0); - state.SetButton(Buttons.B, (info.Buttons & 1 << 1) != 0); - state.SetButton(Buttons.X, (info.Buttons & 1 << 2) != 0); - state.SetButton(Buttons.Y, (info.Buttons & 1 << 3) != 0); - state.SetButton(Buttons.LeftShoulder, (info.Buttons & 1 << 4) != 0); - state.SetButton(Buttons.RightShoulder, (info.Buttons & 1 << 5) != 0); - state.SetButton(Buttons.Back, (info.Buttons & 1 << 6) != 0); - state.SetButton(Buttons.Start, (info.Buttons & 1 << 7) != 0); - state.SetButton(Buttons.LeftStick, (info.Buttons & 1 << 8) != 0); - state.SetButton(Buttons.RightStick, (info.Buttons & 1 << 9) != 0); - state.SetButton(Buttons.BigButton, (info.Buttons & 1 << 10) != 0); - } - else - { - Debug.Print("[Win] Invalid WinMM joystick device {0}", index); - } - - return state; - } - - public string GetName(int index) - { - throw new NotImplementedException(); - } - - #endregion } } From 890d56ae63c978789211096facaafe853f3daea5 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 14:24:42 +0100 Subject: [PATCH 107/154] Connected XInput driver --- Source/OpenTK/Platform/Windows/WinRawInput.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinRawInput.cs b/Source/OpenTK/Platform/Windows/WinRawInput.cs index 04025efd..08e57201 100644 --- a/Source/OpenTK/Platform/Windows/WinRawInput.cs +++ b/Source/OpenTK/Platform/Windows/WinRawInput.cs @@ -43,7 +43,8 @@ namespace OpenTK.Platform.Windows WinRawKeyboard keyboard_driver; WinRawMouse mouse_driver; - WinMMJoystick joystick_driver; + IGamePadDriver gamepad_driver; + IJoystickDriver2 joystick_driver; IntPtr DevNotifyHandle; static readonly Guid DeviceInterfaceHid = new Guid("4D1E55B2-F16F-11CF-88CB-001111000030"); @@ -138,6 +139,15 @@ namespace OpenTK.Platform.Windows keyboard_driver = new WinRawKeyboard(Parent.Handle); mouse_driver = new WinRawMouse(Parent.Handle); joystick_driver = new WinMMJoystick(); + try + { + gamepad_driver = new XInputJoystick(); + } + catch (Exception e) + { + Debug.Print("[Win] XInput driver not supported, falling back to WinMM"); + gamepad_driver = new MappedGamePadDriver(); + } DevNotifyHandle = RegisterForDeviceNotifications(Parent); } @@ -187,12 +197,12 @@ namespace OpenTK.Platform.Windows public override IGamePadDriver GamePadDriver { - get { return joystick_driver; } + get { return gamepad_driver; } } public override IJoystickDriver2 JoystickDriver { - get { throw new NotImplementedException(); } + get { return joystick_driver; } } #endregion From 82a2c9113cb33ec08bd97fa1ccb9397885ebd6d3 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 15:01:10 +0100 Subject: [PATCH 108/154] Implemented structural equality --- Source/OpenTK/Input/JoystickCapabilities.cs | 39 ++++++++++- Source/OpenTK/Input/JoystickState.cs | 73 ++++++++++++++++++--- 2 files changed, 101 insertions(+), 11 deletions(-) diff --git a/Source/OpenTK/Input/JoystickCapabilities.cs b/Source/OpenTK/Input/JoystickCapabilities.cs index b25fa69b..80036211 100644 --- a/Source/OpenTK/Input/JoystickCapabilities.cs +++ b/Source/OpenTK/Input/JoystickCapabilities.cs @@ -33,7 +33,7 @@ using System.Text; namespace OpenTK.Input { - public struct JoystickCapabilities + public struct JoystickCapabilities : IEquatable { byte axis_count; byte button_count; @@ -69,6 +69,33 @@ namespace OpenTK.Input get { return button_count; } } + public bool IsConnected + { + get { return is_connected; } + } + + public override string ToString() + { + return String.Format( + "{{Axes: {0}; Buttons: {1}; IsConnected: {2}}}", + AxisCount, ButtonCount, IsConnected); + } + + public override int GetHashCode() + { + return + AxisCount.GetHashCode() ^ + ButtonCount.GetHashCode() ^ + IsConnected.GetHashCode(); + } + + public override bool Equals(object obj) + { + return + obj is JoystickCapabilities && + Equals((JoystickCapabilities)obj); + } + #endregion #region Private Members @@ -80,10 +107,16 @@ namespace OpenTK.Input #endregion - public bool IsConnected + #region IEquatable Members + + public bool Equals(JoystickCapabilities other) { - get { return is_connected; } + return + AxisCount == other.AxisCount && + ButtonCount == other.ButtonCount && + IsConnected == other.IsConnected; } + #endregion } } diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index 8a233df6..1b2a1299 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -34,7 +34,7 @@ using System.Text; namespace OpenTK.Input { - public struct JoystickState + public struct JoystickState : IEquatable { // If we ever add more values to JoystickAxis or JoystickButton // then we'll need to increase these limits. @@ -59,13 +59,7 @@ namespace OpenTK.Input float value = 0.0f; if (axis >= 0 && axis < MaxAxes) { - unsafe - { - fixed (short* paxis = axes) - { - value = *(paxis + axis) * ConversionFactor; - } - } + value = GetAxisUnsafe(axis) * ConversionFactor; } else { @@ -94,6 +88,38 @@ namespace OpenTK.Input get { return is_connected; } } + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < MaxAxes; i++) + { + sb.Append(" "); + sb.Append(GetAxis(i)); + } + return String.Format( + "{{Axes:{0}; Buttons: {1}; IsConnected: {2}}}", + sb.ToString(), + Convert.ToString((int)buttons, 2), + IsConnected); + } + + public override int GetHashCode() + { + int hash = buttons.GetHashCode() ^ IsConnected.GetHashCode(); + for (int i = 0; i < MaxAxes; i++) + { + hash ^= GetAxisUnsafe(i).GetHashCode(); + } + return hash; + } + + public override bool Equals(object obj) + { + return + obj is JoystickState && + Equals((JoystickState)obj); + } + #endregion #region Internal Members @@ -132,5 +158,36 @@ namespace OpenTK.Input } #endregion + + #region Private Members + + short GetAxisUnsafe(int index) + { + unsafe + { + fixed (short* paxis = axes) + { + return *(paxis + index); + } + } + } + + #endregion + + #region IEquatable Members + + public bool Equals(JoystickState other) + { + bool equals = + buttons == other.buttons && + IsConnected == other.IsConnected; + for (int i = 0; equals && i < MaxAxes; i++) + { + equals &= GetAxisUnsafe(i) == other.GetAxisUnsafe(i); + } + return equals; + } + + #endregion } } From d33d0c7387cb2e9b13d34d842b36b30a154629d6 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 15:01:33 +0100 Subject: [PATCH 109/154] Added state output for OpenTK.Input.Joystick --- .../Examples/OpenTK/Test/GameWindowStates.cs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 8359a552..aa9d27d2 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -228,14 +228,31 @@ namespace Examples.Tests int DrawGamePads(Graphics gfx, int line) { + line++; DrawString(gfx, "GamePads:", line++); for (int i = 0; i < 4; i++) { GamePadCapabilities caps = GamePad.GetCapabilities(i); GamePadState state = GamePad.GetState(i); - DrawString(gfx, caps.ToString(), line++); - DrawString(gfx, state.ToString(), line++); + if (state.IsConnected) + { + DrawString(gfx, caps.ToString(), line++); + DrawString(gfx, state.ToString(), line++); + } } + line++; + DrawString(gfx, "Joysticks:", line++); + for (int i = 0; i < 4; i++) + { + JoystickCapabilities caps = Joystick.GetCapabilities(i); + JoystickState state = Joystick.GetState(i); + if (state.IsConnected) + { + DrawString(gfx, caps.ToString(), line++); + DrawString(gfx, state.ToString(), line++); + } + } + return line; } From f3cb578587d614281f7801549318f02524d7d63b Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 15:51:25 +0100 Subject: [PATCH 110/154] Improved WinMMJoystickDriver hotplugging behavior --- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 882ce5f0..9f84c09e 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -133,6 +133,16 @@ namespace OpenTK.Platform.Windows return stick; } + void UnplugJoystick(int index) + { + // Reset the system configuration. Without this, + // joysticks that are reconnected on different + // ports are given different ids, making it + // impossible to reconnect a disconnected user. + UnsafeNativeMethods.joyConfigChanged(0); + Debug.Print("[Win] WinMM joystick {0} unplugged", index); + } + bool IsValid(int index) { return index >= 0 && index < UnsafeNativeMethods.joyGetNumDevs(); @@ -258,6 +268,10 @@ namespace OpenTK.Platform.Windows // gpcaps.DPadCount++; return caps; } + else if (result == JoystickError.Unplugged) + { + UnplugJoystick(index); + } } else { @@ -276,18 +290,32 @@ namespace OpenTK.Platform.Windows JoyInfoEx info = new JoyInfoEx(); info.Size = JoyInfoEx.SizeInBytes; info.Flags = JoystickFlags.All; - UnsafeNativeMethods.joyGetPosEx(index, ref info); - state.SetAxis(JoystickAxis.Axis0, (short)info.XPos); - state.SetAxis(JoystickAxis.Axis1, (short)info.YPos); - state.SetAxis(JoystickAxis.Axis2, (short)info.ZPos); - state.SetAxis(JoystickAxis.Axis3, (short)info.RPos); - state.SetAxis(JoystickAxis.Axis4, (short)info.ZPos); - state.SetAxis(JoystickAxis.Axis5, (short)info.RPos); - - for (int i = 0; i < 16; i++) + JoystickError result = UnsafeNativeMethods.joyGetPosEx(index, ref info); + if (result == JoystickError.NoError) { - state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); + state.SetAxis(JoystickAxis.Axis0, (short)info.XPos); + state.SetAxis(JoystickAxis.Axis1, (short)info.YPos); + state.SetAxis(JoystickAxis.Axis2, (short)info.ZPos); + state.SetAxis(JoystickAxis.Axis3, (short)info.RPos); + state.SetAxis(JoystickAxis.Axis4, (short)info.ZPos); + state.SetAxis(JoystickAxis.Axis5, (short)info.RPos); + + for (int i = 0; i < 16; i++) + { + state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); + } + + state.SetIsConnected(true); + } + else if (result == JoystickError.Unplugged) + { + UnplugJoystick(index); + } + else + { + // Joystick not existent or other error. No need to spam the log + //Debug.Print("[Win] WinMM joyGetPosEx failed. Error: {0}", result); } } else @@ -441,9 +469,11 @@ namespace OpenTK.Platform.Windows [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity] public static extern JoystickError joyGetDevCaps(int uJoyID, out JoyCaps pjc, int cbjc); [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity] - public static extern uint joyGetPosEx(int uJoyID, ref JoyInfoEx pji); + public static extern JoystickError joyGetPosEx(int uJoyID, ref JoyInfoEx pji); [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity] public static extern int joyGetNumDevs(); + [DllImport("Winmm.dll"), SuppressUnmanagedCodeSecurity] + public static extern JoystickError joyConfigChanged(int flags); } #endregion From 9a90772ceff5779ff0eccd93187d51d59d1be016 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 16:42:48 +0100 Subject: [PATCH 111/154] Fixed WinMM offsets for IJoystickDevice2 --- .../OpenTK/Platform/Windows/WinMMJoystick.cs | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index 9f84c09e..fa84aba1 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -148,6 +148,12 @@ namespace OpenTK.Platform.Windows return index >= 0 && index < UnsafeNativeMethods.joyGetNumDevs(); } + static short CalculateOffset(int pos, int min, int max) + { + int offset = (ushort.MaxValue * (pos - min)) / (max - min) - short.MaxValue; + return (short)offset; + } + #endregion #region IJoystickDriver @@ -294,29 +300,30 @@ namespace OpenTK.Platform.Windows JoystickError result = UnsafeNativeMethods.joyGetPosEx(index, ref info); if (result == JoystickError.NoError) { - state.SetAxis(JoystickAxis.Axis0, (short)info.XPos); - state.SetAxis(JoystickAxis.Axis1, (short)info.YPos); - state.SetAxis(JoystickAxis.Axis2, (short)info.ZPos); - state.SetAxis(JoystickAxis.Axis3, (short)info.RPos); - state.SetAxis(JoystickAxis.Axis4, (short)info.ZPos); - state.SetAxis(JoystickAxis.Axis5, (short)info.RPos); - - for (int i = 0; i < 16; i++) + JoyCaps caps; + result = UnsafeNativeMethods.joyGetDevCaps(index, out caps, JoyCaps.SizeInBytes); + if (result == JoystickError.NoError) { - state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); - } + state.SetAxis(JoystickAxis.Axis0, CalculateOffset(info.XPos, caps.XMin, caps.XMax)); + state.SetAxis(JoystickAxis.Axis1, CalculateOffset(info.YPos, caps.YMin, caps.YMax)); + state.SetAxis(JoystickAxis.Axis2, CalculateOffset(info.ZPos, caps.ZMin, caps.ZMax)); + state.SetAxis(JoystickAxis.Axis3, CalculateOffset(info.RPos, caps.RMin, caps.RMax)); + state.SetAxis(JoystickAxis.Axis4, CalculateOffset(info.UPos, caps.UMin, caps.UMax)); + state.SetAxis(JoystickAxis.Axis5, CalculateOffset(info.VPos, caps.VMin, caps.VMax)); - state.SetIsConnected(true); + for (int i = 0; i < 16; i++) + { + state.SetButton(JoystickButton.Button0 + i, (info.Buttons & 1 << i) != 0); + } + + state.SetIsConnected(true); + } } - else if (result == JoystickError.Unplugged) + + if (result == JoystickError.Unplugged) { UnplugJoystick(index); } - else - { - // Joystick not existent or other error. No need to spam the log - //Debug.Print("[Win] WinMM joyGetPosEx failed. Error: {0}", result); - } } else { From 7fd7b8c7a255ce6c4a2a18883a715e1f732f7c97 Mon Sep 17 00:00:00 2001 From: Stefanos A Date: Tue, 24 Dec 2013 17:06:39 +0100 Subject: [PATCH 112/154] Improved ToString implementation --- Source/OpenTK/Input/GamePadButtons.cs | 14 +------------- Source/OpenTK/Input/GamePadThumbSticks.cs | 4 ++-- Source/OpenTK/Input/GamePadTriggers.cs | 2 +- Source/OpenTK/Input/Joystick.cs | 5 +++++ Source/OpenTK/Input/JoystickState.cs | 6 +++--- 5 files changed, 12 insertions(+), 19 deletions(-) diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index aeb97b59..c13a9f0c 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -109,19 +109,7 @@ namespace OpenTK.Input public override string ToString() { - return String.Format( - "{{{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}}}", - A == ButtonState.Pressed ? "A" : String.Empty, - B == ButtonState.Pressed ? "B" : String.Empty, - X == ButtonState.Pressed ? "X" : String.Empty, - Y == ButtonState.Pressed ? "Y" : String.Empty, - LeftShoulder == ButtonState.Pressed ? "L" : String.Empty, - RightShoulder == ButtonState.Pressed ? "R" : String.Empty, - Back == ButtonState.Pressed ? " Back" : String.Empty, - Start == ButtonState.Pressed ? " Start" : String.Empty, - BigButton == ButtonState.Pressed ? " Big" : String.Empty, - LeftStick == ButtonState.Pressed ? " LStick" : String.Empty, - RightStick == ButtonState.Pressed ? " RStick" : String.Empty); + return Convert.ToString((int)buttons, 2).PadLeft(10, '0'); } public override int GetHashCode() diff --git a/Source/OpenTK/Input/GamePadThumbSticks.cs b/Source/OpenTK/Input/GamePadThumbSticks.cs index 59eb4ee3..63838c6f 100644 --- a/Source/OpenTK/Input/GamePadThumbSticks.cs +++ b/Source/OpenTK/Input/GamePadThumbSticks.cs @@ -73,8 +73,8 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Left: {0}; Right: {1}}}", - Left, Right); + "{{Left: ({0:f4}; {1:f4}); Right: ({2:f4}; {3:f4})}}", + Left.X, Left.Y, Right.X, Right.Y); } public override int GetHashCode() diff --git a/Source/OpenTK/Input/GamePadTriggers.cs b/Source/OpenTK/Input/GamePadTriggers.cs index ecff49c7..0e505d81 100644 --- a/Source/OpenTK/Input/GamePadTriggers.cs +++ b/Source/OpenTK/Input/GamePadTriggers.cs @@ -69,7 +69,7 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Left: {0}; Right: {1}}}", + "{{Left: {0:f2}; Right: {1:f2}}}", Left, Right); } diff --git a/Source/OpenTK/Input/Joystick.cs b/Source/OpenTK/Input/Joystick.cs index 0458abed..378b11f4 100644 --- a/Source/OpenTK/Input/Joystick.cs +++ b/Source/OpenTK/Input/Joystick.cs @@ -47,5 +47,10 @@ namespace OpenTK.Input { return implementation.GetState(index); } + + //public string GetName(int index) + //{ + // return implementation.GetName(index); + //} } } diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index 1b2a1299..e14ac2d2 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -41,7 +41,7 @@ namespace OpenTK.Input internal const int MaxAxes = 10; internal const int MaxButtons = 32; - const float ConversionFactor = 1.0f / (short.MaxValue + 1); + const float ConversionFactor = 1.0f / (short.MaxValue + 0.5f); unsafe fixed short axes[MaxAxes]; int buttons; @@ -94,12 +94,12 @@ namespace OpenTK.Input for (int i = 0; i < MaxAxes; i++) { sb.Append(" "); - sb.Append(GetAxis(i)); + sb.Append(String.Format("{0:f4}", GetAxis(i))); } return String.Format( "{{Axes:{0}; Buttons: {1}; IsConnected: {2}}}", sb.ToString(), - Convert.ToString((int)buttons, 2), + Convert.ToString((int)buttons, 2).PadLeft(16, '0'), IsConnected); } From 1eb807bb64aee69204674cd0328313bef3574394 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 24 Dec 2013 17:16:16 +0100 Subject: [PATCH 113/154] Use IGamePadDriver through MappedGamePadDriver --- Source/OpenTK/Platform/MacOS/HIDInput.cs | 30 +++++------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index 613d1c64..0967afef 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -50,7 +50,7 @@ namespace OpenTK.Platform.MacOS // Requires Mac OS X 10.5 or higher. // Todo: create a driver for older installations. Maybe use CGGetLastMouseDelta for that? - class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IGamePadDriver, IJoystickDriver2 + class HIDInput : IInputDriver2, IMouseDriver2, IKeyboardDriver2, IJoystickDriver2 { #region Fields @@ -69,6 +69,8 @@ namespace OpenTK.Platform.MacOS readonly CFString InputLoopMode = CF.RunLoopModeDefault; readonly CFDictionary DeviceTypes = new CFDictionary(); + readonly MappedGamePadDriver mapped_gamepad = new MappedGamePadDriver(); + NativeMethods.IOHIDDeviceCallback HandleDeviceAdded; NativeMethods.IOHIDDeviceCallback HandleDeviceRemoved; NativeMethods.IOHIDValueCallback HandleDeviceValueReceived; @@ -291,10 +293,9 @@ namespace OpenTK.Platform.MacOS public IMouseDriver2 MouseDriver { get { return this; } } public IKeyboardDriver2 KeyboardDriver { get { return this; } } - public IGamePadDriver GamePadDriver { get { return this; } } + public IGamePadDriver GamePadDriver { get { return mapped_gamepad; } } public IJoystickDriver2 JoystickDriver { get { return this; } } - #endregion #region IMouseDriver2 Members @@ -368,35 +369,16 @@ namespace OpenTK.Platform.MacOS #endregion - #region IGamePadDriver Members - - public GamePadState GetState(int index) - { - return new GamePadState(); - } - - public GamePadCapabilities GetCapabilities(int index) - { - return new GamePadCapabilities(); - } - - public string GetName(int index) - { - throw new NotImplementedException(); - } - - #endregion - #region IJoystickDriver2 Members JoystickState IJoystickDriver2.GetState(int index) { - throw new NotImplementedException(); + return new JoystickState(); } JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) { - throw new NotImplementedException(); + return new JoystickCapabilities(); } #endregion From 6fc679c4ba830eedfc53e6d70295a062a8991e2a Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 24 Dec 2013 19:14:35 +0100 Subject: [PATCH 114/154] Removed duplicate button types --- Source/OpenTK/Input/Buttons.cs | 54 ++-------------------------------- 1 file changed, 3 insertions(+), 51 deletions(-) diff --git a/Source/OpenTK/Input/Buttons.cs b/Source/OpenTK/Input/Buttons.cs index 739a8fcd..5d3889e7 100644 --- a/Source/OpenTK/Input/Buttons.cs +++ b/Source/OpenTK/Input/Buttons.cs @@ -27,6 +27,9 @@ using System; namespace OpenTK.Input { + /// + /// Enumerates available buttons for a canonical GamePad device. + /// public enum Buttons { /// @@ -158,56 +161,5 @@ namespace OpenTK.Input /// Left stick right direction button /// LeftThumbstickRight = 1 << 30, - - /// The first button of the gamepad. - Button0 = A, - /// The second button of the gamepad. - Button1 = B, - /// The third button of the gamepad. - Button2 = X, - /// The fourth button of the gamepad. - Button3 = Y, - /// The fifth button of the gamepad. - Button4 = Start, - /// The sixth button of the gamepad. - Button5 = Back, - /// The seventh button of the gamepad. - Button6 = LeftStick, - /// The eighth button of the gamepad. - Button7 = RightStick, - /// The ninth button of the gamepad. - Button8 = LeftShoulder, - /// The tenth button of the gamepad. - Button9 = RightShoulder, - /// The eleventh button of the gamepad. - Button10 = Home, - /// The twelfth button of the gamepad. - Button11 = DPadUp, - /// The thirteenth button of the gamepad. - Button12 = DPadDown, - /// The fourteenth button of the gamepad. - Button13 = DPadLeft, - /// The fifteenth button of the gamepad. - Button14 = DPadRight, - /// The sixteenth button of the gamepad. - Button15 = LeftTrigger, - /// The seventeenth button of the gamepad. - Button16 = RightTrigger, - /// The eighteenth button of the gamepad. - Button17 = LeftThumbstickUp, - /// The nineteenth button of the gamepad. - Button18 = LeftThumbstickDown, - /// The twentieth button of the gamepad. - Button19 = LeftThumbstickLeft, - /// The twentieth-one button of the gamepad. - Button20 = LeftThumbstickRight, - /// The twentieth-one button of the gamepad. - Button21 = RightThumbstickUp, - /// The twentieth-one button of the gamepad. - Button22 = RightThumbstickDown, - /// The twentieth-one button of the gamepad. - Button23 = RightThumbstickLeft, - /// The twentieth-one button of the gamepad. - Button24 = RightThumbstickRight, } } From c51c4934df348442818a9906eebcdb2ea46dbc2b Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 24 Dec 2013 19:14:54 +0100 Subject: [PATCH 115/154] Added GameControllerGetBind APIs --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 55 ++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 163d393b..5aa6dad4 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -137,7 +137,28 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetAxis", ExactSpelling = true)] public static extern short GameControllerGetAxis(IntPtr gamecontroller, GameControllerAxis axis); - /// > + /// + /// Gets the SDL joystick layer binding for the specified game controller axis + /// + /// Pointer to a game controller instance returned by GameControllerOpen. + /// A value from the GameControllerAxis enumeration + /// A GameControllerButtonBind instance describing the specified binding + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetBindForAxis", ExactSpelling = true)] + public static extern GameControllerButtonBind GameControllerGetBindForAxis(IntPtr gamecontroller, GameControllerAxis axis); + + /// + /// Gets the SDL joystick layer binding for the specified game controller button + /// + /// Pointer to a game controller instance returned by GameControllerOpen. + /// A value from the GameControllerButton enumeration + /// A GameControllerButtonBind instance describing the specified binding + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetBindForButton", ExactSpelling = true)] + public static extern GameControllerButtonBind GameControllerGetBindForButton( + IntPtr gamecontroller, GameControllerButton button); + + /// /// Gets the current state of a button on a game controller. /// /// A game controller handle previously opened with GameControllerOpen. @@ -147,6 +168,15 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetButton", ExactSpelling = true)] public static extern bool GameControllerGetButton(IntPtr gamecontroller, GameControllerButton button); + /// + /// Retrieve the joystick handle that corresponds to the specified game controller. + /// + /// A game controller handle previously opened with GameControllerOpen. + /// A handle to a joystick, or IntPtr.Zero in case of error. The pointer is owned by the callee. Use SDL.GetError to retrieve error information + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetJoystick", ExactSpelling = true)] + public static extern IntPtr GameControllerGetJoystick(IntPtr gamecontroller); + /// /// Opens a game controller for use. /// @@ -587,6 +617,14 @@ namespace OpenTK.Platform.SDL2 Max } + enum GameControllerBindType : byte + { + None = 0, + Button, + Axis, + Hat + } + [Flags] enum HatPosition : byte { @@ -1277,6 +1315,21 @@ namespace OpenTK.Platform.SDL2 #endif } + [StructLayout(LayoutKind.Explicit)] + struct GameControllerButtonBind + { + [FieldOffset(0)] + public GameControllerBindType BindType; + [FieldOffset(4)] + public Button Button; + [FieldOffset(4)] + public GameControllerAxis Axis; + [FieldOffset(4)] + public int Hat; + [FieldOffset(8)] + public int HatMask; + } + struct JoyAxisEvent { public EventType Type; From b4b8bc1665f189a3ddc63de4f167ff6f5b5833e2 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 24 Dec 2013 19:15:23 +0100 Subject: [PATCH 116/154] Implemented SDL IJoystickDriver2 and IGamePadDriver --- .../Platform/SDL2/Sdl2JoystickDriver.cs | 116 ++++++++++++++++-- 1 file changed, 106 insertions(+), 10 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index d5caa2c1..7e5cd955 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -48,6 +48,7 @@ namespace OpenTK.Platform.SDL2 { public IntPtr Handle { get; private set; } public GamePadState State { get; set; } + public GamePadCapabilities Capabilities { get; set; } public Sdl2GamePad(IntPtr handle) { @@ -114,6 +115,53 @@ namespace OpenTK.Platform.SDL2 return controllers.ContainsKey(id); } + GamePadAxes TranslateAxes(IntPtr gamecontroller) + { + GamePadAxes axes = 0; + axes |= IsAxisBind(gamecontroller, GameControllerAxis.LeftX) ? GamePadAxes.LeftX : 0; + axes |= IsAxisBind(gamecontroller, GameControllerAxis.LeftY) ? GamePadAxes.LeftY : 0; + axes |= IsAxisBind(gamecontroller, GameControllerAxis.RightX) ? GamePadAxes.RightX : 0; + axes |= IsAxisBind(gamecontroller, GameControllerAxis.RightY) ? GamePadAxes.RightY : 0; + axes |= IsAxisBind(gamecontroller, GameControllerAxis.TriggerLeft) ? GamePadAxes.LeftTrigger : 0; + axes |= IsAxisBind(gamecontroller, GameControllerAxis.TriggerRight) ? GamePadAxes.RightTrigger : 0; + return axes; + } + + Buttons TranslateButtons(IntPtr gamecontroller) + { + Buttons buttons = 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.A) ? Buttons.A : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.B) ? Buttons.B : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.X) ? Buttons.X : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.Y) ? Buttons.Y : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.START) ? Buttons.Start : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.BACK) ? Buttons.Back : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.LEFTSHOULDER) ? Buttons.LeftShoulder : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.RIGHTSHOULDER) ? Buttons.RightShoulder : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.LEFTSTICK) ? Buttons.LeftStick : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.RIGHTSTICK) ? Buttons.RightStick : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.GUIDE) ? Buttons.BigButton : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.DPAD_DOWN) ? Buttons.DPadDown : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.DPAD_UP) ? Buttons.DPadUp : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.DPAD_LEFT) ? Buttons.DPadLeft : 0; + buttons |= IsButtonBind(gamecontroller, GameControllerButton.DPAD_RIGHT) ? Buttons.DPadRight : 0; + return buttons; + } + + bool IsAxisBind(IntPtr gamecontroller, GameControllerAxis axis) + { + GameControllerButtonBind bind = + SDL.GameControllerGetBindForAxis(gamecontroller, axis); + return bind.BindType == GameControllerBindType.Axis; + } + + bool IsButtonBind(IntPtr gamecontroller, GameControllerButton button) + { + GameControllerButtonBind bind = + SDL.GameControllerGetBindForButton(gamecontroller, button); + return bind.BindType == GameControllerBindType.Axis; + } + #endregion #region Public Members @@ -232,11 +280,27 @@ namespace OpenTK.Platform.SDL2 if (handle != IntPtr.Zero) { Sdl2GamePad pad = new Sdl2GamePad(handle); - pad.State.SetConnected(true); - // Check whether the device has ever been connected before - if (!controllers.ContainsKey(id)) - controllers.Add(id, null); - controllers[id] = pad; + + IntPtr joystick = SDL.GameControllerGetJoystick(handle); + if (joystick != IntPtr.Zero) + { + SDL.JoystickNumAxes(joystick); + pad.Capabilities = new GamePadCapabilities( + GamePadType.GamePad, + TranslateAxes(joystick), + TranslateButtons(joystick), + true); + pad.State.SetConnected(true); + + // Check whether the device has ever been connected before + if (!controllers.ContainsKey(id)) + controllers.Add(id, null); + controllers[id] = pad; + } + else + { + Debug.Print("[SDL2] Failed to retrieve joystick from game controller. Error: {0}", SDL.GetError()); + } } break; @@ -302,16 +366,19 @@ namespace OpenTK.Platform.SDL2 public GamePadCapabilities GetCapabilities(int index) { + if (IsControllerValid(index)) + { + return controllers[index].Capabilities; + } return new GamePadCapabilities(); } public GamePadState GetState(int index) { - if (joysticks.Count >= index) + if (IsControllerValid(index)) { - + return controllers[index].State; } - return new GamePadState(); } @@ -326,12 +393,41 @@ namespace OpenTK.Platform.SDL2 JoystickState IJoystickDriver2.GetState(int index) { - throw new NotImplementedException(); + JoystickState state = new JoystickState(); + if (IsJoystickValid(index)) + { + JoystickDevice joystick = + (JoystickDevice)joysticks[sdl_joyid_to_joysticks[index]]; + + for (int i = 0; i < joystick.Axis.Count; i++) + { + state.SetAxis(JoystickAxis.Axis0 + i, (short)(joystick.Axis[i] * short.MaxValue + 0.5f)); + } + + for (int i = 0; i < joystick.Button.Count; i++) + { + state.SetButton(JoystickButton.Button0 + i, joystick.Button[i]); + } + + state.SetIsConnected(true); + } + + return state; } JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) { - throw new NotImplementedException(); + if (IsJoystickValid(index)) + { + JoystickDevice joystick = + (JoystickDevice)joysticks[sdl_joyid_to_joysticks[index]]; + + return new JoystickCapabilities( + joystick.Axis.Count, + joystick.Button.Count, + true); + } + return new JoystickCapabilities(); } #endregion From f7fbf38c43ee0543172f59391403e6ed79533196 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Wed, 25 Dec 2013 01:47:27 +0100 Subject: [PATCH 117/154] IsButtonBind should check for buttons, not axes --- Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 7e5cd955..5d014d0b 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -159,7 +159,7 @@ namespace OpenTK.Platform.SDL2 { GameControllerButtonBind bind = SDL.GameControllerGetBindForButton(gamecontroller, button); - return bind.BindType == GameControllerBindType.Axis; + return bind.BindType == GameControllerBindType.Button; } #endregion From e997ddf9c636bb773b84d5146dab03330105a6c8 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 13:39:43 +0100 Subject: [PATCH 118/154] [Input] Fixed GamePadState.SetAxis() implementation GamePadState.SetAxis() receives a GamePadAxes enumeration, which is a bitmask of the axes we wish to set. SetAxis now correctly decodes the bitmask to apply the values we are interested in. --- Source/OpenTK/Input/GamePadState.cs | 40 ++++++++++++++++++----------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index bd196982..76db81aa 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -111,26 +111,36 @@ namespace OpenTK.Input internal void SetAxis(GamePadAxes axis, short value) { - switch (axis) + if ((axis & GamePadAxes.LeftX) != 0) { - case GamePadAxes.LeftX: - left_stick_x = value; - break; + left_stick_x = value; + } - case GamePadAxes.LeftY: - left_stick_y = value; - break; + if ((axis & GamePadAxes.LeftY) != 0) + { + left_stick_y = value; + } - case GamePadAxes.RightX: - right_stick_x = value; - break; + if ((axis & GamePadAxes.RightX) != 0) + { + right_stick_x = value; + } - case GamePadAxes.RightY: - right_stick_y = value; - break; + if ((axis & GamePadAxes.RightY) != 0) + { + right_stick_y = value; + } - default: - throw new ArgumentOutOfRangeException("axis"); + if ((axis & GamePadAxes.LeftTrigger) != 0) + { + // Adjust from [-32768, 32767] to [0, 255] + left_trigger = (byte)((ev.Value - short.MinValue) >> 8); + } + + if ((axis & GamePadAxes.RightTrigger) != 0) + { + // Adjust from [-32768, 32767] to [0, 255] + right_trigger = (byte)((ev.Value - short.MinValue) >> 8); } } From 1b0a72472e76aaac99b4c9966d8faf285bf7c1ba Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 13:42:37 +0100 Subject: [PATCH 119/154] [SDL] Use TranslateAxis() to decode ControllerAxisEvent SDL GameControllerAxis and GamePadAxes are not interchangeable. The driver will now correctly interpret incoming SDL messages and update the GamePadState for the relevant axis. --- .../Platform/SDL2/Sdl2JoystickDriver.cs | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 5d014d0b..6c08c77e 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -115,7 +115,7 @@ namespace OpenTK.Platform.SDL2 return controllers.ContainsKey(id); } - GamePadAxes TranslateAxes(IntPtr gamecontroller) + GamePadAxes GetBoundAxes(IntPtr gamecontroller) { GamePadAxes axes = 0; axes |= IsAxisBind(gamecontroller, GameControllerAxis.LeftX) ? GamePadAxes.LeftX : 0; @@ -127,7 +127,7 @@ namespace OpenTK.Platform.SDL2 return axes; } - Buttons TranslateButtons(IntPtr gamecontroller) + Buttons GetBoundButtons(IntPtr gamecontroller) { Buttons buttons = 0; buttons |= IsButtonBind(gamecontroller, GameControllerButton.A) ? Buttons.A : 0; @@ -162,6 +162,33 @@ namespace OpenTK.Platform.SDL2 return bind.BindType == GameControllerBindType.Button; } + GamePadAxes TranslateAxis(GameControllerAxis axis) + { + switch (axis) + { + case GameControllerAxis.LeftX: + return GamePadAxes.LeftX; + + case GameControllerAxis.LeftY: + return GamePadAxes.LeftY; + + case GameControllerAxis.RightX: + return GamePadAxes.RightX; + + case GameControllerAxis.RightY: + return GamePadAxes.RightY; + + case GameControllerAxis.TriggerLeft: + return GamePadAxes.LeftTrigger; + + case GameControllerAxis.TriggerRight: + return GamePadAxes.RightTrigger; + + default: + throw new ArgumentOutOfRangeException( + String.Format("[SDL] Unknown axis {0}", axis)); + } + } #endregion #region Public Members @@ -287,8 +314,8 @@ namespace OpenTK.Platform.SDL2 SDL.JoystickNumAxes(joystick); pad.Capabilities = new GamePadCapabilities( GamePadType.GamePad, - TranslateAxes(joystick), - TranslateButtons(joystick), + GetBoundAxes(joystick), + GetBoundButtons(joystick), true); pad.State.SetConnected(true); @@ -322,7 +349,7 @@ namespace OpenTK.Platform.SDL2 int id = ev.Which; if (IsControllerValid(id)) { - controllers[id].State.SetAxis((GamePadAxes)ev.Axis, ev.Value); + controllers[id].State.SetAxis(TranslateAxis(ev.Axis), ev.Value); } else { From 064a45e4a7356fc5de3ea093cc102d849c6d675c Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 13:49:26 +0100 Subject: [PATCH 120/154] [Input] Fixed incorrect variable name --- Source/OpenTK/Input/GamePadState.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index 76db81aa..096d3daf 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -134,13 +134,13 @@ namespace OpenTK.Input if ((axis & GamePadAxes.LeftTrigger) != 0) { // Adjust from [-32768, 32767] to [0, 255] - left_trigger = (byte)((ev.Value - short.MinValue) >> 8); + left_trigger = (byte)((value - short.MinValue) >> 8); } if ((axis & GamePadAxes.RightTrigger) != 0) { // Adjust from [-32768, 32767] to [0, 255] - right_trigger = (byte)((ev.Value - short.MinValue) >> 8); + right_trigger = (byte)((value - short.MinValue) >> 8); } } From a4366e52f52fadd9f865ec2314aad4cee10c247e Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 14:56:22 +0100 Subject: [PATCH 121/154] [Input] Added missing closing brace in ToString() message --- Source/OpenTK/Input/GamePadState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index 096d3daf..179762b3 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -75,7 +75,7 @@ namespace OpenTK.Input public override string ToString() { return String.Format( - "{{Sticks: {0}; Buttons: {1}; DPad: {2}; IsConnected: {3}", + "{{Sticks: {0}; Buttons: {1}; DPad: {2}; IsConnected: {3}}}", ThumbSticks, Buttons, DPad, IsConnected); } From 52b8762593f1d8b58f9933df3a53df7985cf50fd Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 14:57:28 +0100 Subject: [PATCH 122/154] [SDL2] Fixed mapping of instance ids to device ids --- .../Platform/SDL2/Sdl2JoystickDriver.cs | 63 ++++++++++++++----- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 6c08c77e..1d616027 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -56,9 +56,12 @@ namespace OpenTK.Platform.SDL2 } } + int last_controllers_instance = 0; + readonly List joysticks = new List(4); readonly Dictionary sdl_joyid_to_joysticks = new Dictionary(); - readonly Dictionary controllers = new Dictionary(); + readonly List controllers = new List(4); + readonly Dictionary sdl_instanceid_to_controllers = new Dictionary(); IList joysticks_readonly; bool disposed; @@ -112,7 +115,12 @@ namespace OpenTK.Platform.SDL2 bool IsControllerValid(int id) { - return controllers.ContainsKey(id); + return id >= 0 && id < controllers.Count; + } + + bool IsControllerInstanceValid(int instance_id) + { + return sdl_instanceid_to_controllers.ContainsKey(instance_id); } GamePadAxes GetBoundAxes(IntPtr gamecontroller) @@ -306,12 +314,20 @@ namespace OpenTK.Platform.SDL2 IntPtr handle = SDL.GameControllerOpen(id); if (handle != IntPtr.Zero) { + // The id variable here corresponds to a device_id between 0 and Sdl.NumJoysticks(). + // It is only used in the ADDED event. All other events use an instance_id which increases + // monotonically in each ADDED event. + // The idea is that device_id refers to the n-th connected joystick, whereas instance_id + // refers to the actual hardware device behind the n-th joystick. + // Yes, it's confusing. + int device_id = id; + int instance_id = last_controllers_instance++; + Sdl2GamePad pad = new Sdl2GamePad(handle); IntPtr joystick = SDL.GameControllerGetJoystick(handle); if (joystick != IntPtr.Zero) { - SDL.JoystickNumAxes(joystick); pad.Capabilities = new GamePadCapabilities( GamePadType.GamePad, GetBoundAxes(joystick), @@ -319,10 +335,17 @@ namespace OpenTK.Platform.SDL2 true); pad.State.SetConnected(true); - // Check whether the device has ever been connected before - if (!controllers.ContainsKey(id)) - controllers.Add(id, null); - controllers[id] = pad; + // Connect this device and add the relevant device index + if (controllers.Count <= id) + { + controllers.Add(pad); + } + else + { + controllers[device_id] = pad; + } + + sdl_instanceid_to_controllers.Add(instance_id, device_id); } else { @@ -332,11 +355,15 @@ namespace OpenTK.Platform.SDL2 break; case EventType.CONTROLLERDEVICEREMOVED: - if (IsControllerValid(id)) { - controllers[id].State.SetConnected(false); + int instance_id = id; + if (IsControllerInstanceValid(id)) + { + controllers[id].State.SetConnected(false); + sdl_instanceid_to_controllers.Remove(instance_id); + } + break; } - break; case EventType.CONTROLLERDEVICEREMAPPED: // Todo: what should we do in this case? @@ -346,27 +373,29 @@ namespace OpenTK.Platform.SDL2 public void ProcessControllerEvent(ControllerAxisEvent ev) { - int id = ev.Which; - if (IsControllerValid(id)) + int instance_id = ev.Which; + if (IsControllerInstanceValid(instance_id)) { - controllers[id].State.SetAxis(TranslateAxis(ev.Axis), ev.Value); + int id = sdl_instanceid_to_controllers[instance_id]; + controllers[id].State.SetAxis(TranslateAxis(ev.Axis), ev.Value); } else { - Debug.Print("[SDL2] Invalid game controller handle {0} in {1}", id, ev.Type); + Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", instance_id, ev.Type); } } public void ProcessControllerEvent(ControllerButtonEvent ev) { - int id = ev.Which; - if (IsControllerValid(id)) + int instance_id = ev.Which; + if (IsControllerInstanceValid(instance_id)) { + int id = sdl_instanceid_to_controllers[instance_id]; controllers[id].State.SetButton((Buttons)ev.Button, ev.State == State.Pressed); } else { - Debug.Print("[SDL2] Invalid game controller handle {0} in {1}", id, ev.Type); + Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", instance_id, ev.Type); } } From 6faa58aac3cf06660bdce3467bae26dab8194427 Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Mon, 30 Dec 2013 15:24:48 +0100 Subject: [PATCH 123/154] [SDL2] Fixed joystick hotplugging SDL2 uses a weird system of device ids and instance ids to report joystick events, where the ADDED event uses a device id and the rest use instance ids. The SDL2 joystick driver is now fixed to correctly distinguish between the two, which fixes hotplugging support for joystick devices. --- .../Platform/SDL2/Sdl2JoystickDriver.cs | 88 +++++++++++++------ 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 1d616027..e284cc59 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -56,10 +56,11 @@ namespace OpenTK.Platform.SDL2 } } + int last_joystick_instance = 0; int last_controllers_instance = 0; readonly List joysticks = new List(4); - readonly Dictionary sdl_joyid_to_joysticks = new Dictionary(); + readonly Dictionary sdl_instanceid_to_joysticks = new Dictionary(); readonly List controllers = new List(4); readonly Dictionary sdl_instanceid_to_controllers = new Dictionary(); @@ -113,6 +114,11 @@ namespace OpenTK.Platform.SDL2 return id >= 0 && id < joysticks.Count; } + bool IsJoystickInstanceValid(int instance_id) + { + return sdl_instanceid_to_joysticks.ContainsKey(instance_id); + } + bool IsControllerValid(int id) { return id >= 0 && id < controllers.Count; @@ -217,28 +223,41 @@ namespace OpenTK.Platform.SDL2 IntPtr handle = SDL.JoystickOpen(id); if (handle != IntPtr.Zero) { + int device_id = id; + int instance_id = last_joystick_instance++; + JoystickDevice joystick = OpenJoystick(id); if (joystick != null) { joystick.Details.IsConnected = true; - if (!sdl_joyid_to_joysticks.ContainsKey(id)) + if (device_id < joysticks.Count) { - sdl_joyid_to_joysticks.Add(id, joysticks.Count); - joysticks.Add(null); + joysticks[device_id] = joystick; } - int index = sdl_joyid_to_joysticks[id]; - joysticks[index] = joystick; + else + { + joysticks.Add(joystick); + } + + sdl_instanceid_to_joysticks.Add(instance_id, device_id); } } } break; case EventType.JOYDEVICEREMOVED: + if (IsJoystickInstanceValid(id)) { - int index = sdl_joyid_to_joysticks[id]; - JoystickDevice joystick = (JoystickDevice)joysticks[index]; + int instance_id = sdl_instanceid_to_joysticks[id]; + sdl_instanceid_to_joysticks.Remove(id); + + JoystickDevice joystick = (JoystickDevice)joysticks[instance_id]; joystick.Details.IsConnected = false; } + else + { + Debug.Print("[SDL2] Invalid joystick id {0} in {1}", id, ev.Type); + } break; } } @@ -246,9 +265,9 @@ namespace OpenTK.Platform.SDL2 public void ProcessJoystickEvent(JoyAxisEvent ev) { int id = ev.Which; - if (IsJoystickValid(id)) + if (IsJoystickInstanceValid(id)) { - int index = sdl_joyid_to_joysticks[id]; + int index = sdl_instanceid_to_joysticks[id]; JoystickDevice joystick = (JoystickDevice)joysticks[index]; float value = ev.Value * RangeMultiplier; joystick.SetAxis((JoystickAxis)ev.Axis, value); @@ -262,9 +281,9 @@ namespace OpenTK.Platform.SDL2 public void ProcessJoystickEvent(JoyBallEvent ev) { int id = ev.Which; - if (IsJoystickValid(id)) + if (IsJoystickInstanceValid(id)) { - int index = sdl_joyid_to_joysticks[id]; + int index = sdl_instanceid_to_joysticks[id]; JoystickDevice joystick = (JoystickDevice)joysticks[index]; // Todo: does it make sense to support balls? } @@ -277,9 +296,9 @@ namespace OpenTK.Platform.SDL2 public void ProcessJoystickEvent(JoyButtonEvent ev) { int id = ev.Which; - if (IsJoystickValid(id)) + if (IsJoystickInstanceValid(id)) { - int index = sdl_joyid_to_joysticks[id]; + int index = sdl_instanceid_to_joysticks[id]; JoystickDevice joystick = (JoystickDevice)joysticks[index]; joystick.SetButton((JoystickButton)ev.Button, ev.State == State.Pressed); } @@ -292,9 +311,9 @@ namespace OpenTK.Platform.SDL2 public void ProcessJoystickEvent(JoyHatEvent ev) { int id = ev.Which; - if (IsJoystickValid(id)) + if (IsJoystickInstanceValid(id)) { - int index = sdl_joyid_to_joysticks[id]; + int index = sdl_instanceid_to_joysticks[id]; JoystickDevice joystick = (JoystickDevice)joysticks[index]; // Todo: map hat to an extra axis } @@ -307,6 +326,11 @@ namespace OpenTK.Platform.SDL2 public void ProcessControllerEvent(ControllerDeviceEvent ev) { int id = ev.Which; + if (id < 0) + { + Debug.Print("[SDL2] Invalid controller id {0} in {1}", id, ev.Type); + return; + } switch (ev.Type) { @@ -355,18 +379,26 @@ namespace OpenTK.Platform.SDL2 break; case EventType.CONTROLLERDEVICEREMOVED: + if (IsControllerInstanceValid(id)) { - int instance_id = id; - if (IsControllerInstanceValid(id)) - { - controllers[id].State.SetConnected(false); - sdl_instanceid_to_controllers.Remove(instance_id); - } - break; + controllers[id].State.SetConnected(false); + sdl_instanceid_to_controllers.Remove(id); } + else + { + Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", id, ev.Type); + } + break; case EventType.CONTROLLERDEVICEREMAPPED: - // Todo: what should we do in this case? + if (IsControllerInstanceValid(id)) + { + // Todo: what should we do in this case? + } + else + { + Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", id, ev.Type); + } break; } } @@ -453,7 +485,7 @@ namespace OpenTK.Platform.SDL2 if (IsJoystickValid(index)) { JoystickDevice joystick = - (JoystickDevice)joysticks[sdl_joyid_to_joysticks[index]]; + (JoystickDevice)joysticks[index]; for (int i = 0; i < joystick.Axis.Count; i++) { @@ -465,7 +497,7 @@ namespace OpenTK.Platform.SDL2 state.SetButton(JoystickButton.Button0 + i, joystick.Button[i]); } - state.SetIsConnected(true); + state.SetIsConnected(joystick.Details.IsConnected); } return state; @@ -476,12 +508,12 @@ namespace OpenTK.Platform.SDL2 if (IsJoystickValid(index)) { JoystickDevice joystick = - (JoystickDevice)joysticks[sdl_joyid_to_joysticks[index]]; + (JoystickDevice)joysticks[index]; return new JoystickCapabilities( joystick.Axis.Count, joystick.Button.Count, - true); + joystick.Details.IsConnected); } return new JoystickCapabilities(); } From 2d303a6884187895af2ec8a6e82f7dcbe458b25f Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 16:07:06 +0100 Subject: [PATCH 124/154] [Input] Buttons should have [Flags] attribute --- Source/OpenTK/Input/Buttons.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Input/Buttons.cs b/Source/OpenTK/Input/Buttons.cs index 5d3889e7..878c738f 100644 --- a/Source/OpenTK/Input/Buttons.cs +++ b/Source/OpenTK/Input/Buttons.cs @@ -30,8 +30,9 @@ namespace OpenTK.Input /// /// Enumerates available buttons for a canonical GamePad device. /// - public enum Buttons - { + [Flags] + public enum Buttons + { /// /// DPad up direction button /// From 9beb396c9ed489dbf8784ffa8dfd32cf7c987212 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 17:08:42 +0100 Subject: [PATCH 125/154] [SDL2] Explicitly enable joystick and gamepad events --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 55 +++++++++++++------ .../OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 3 + 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 5aa6dad4..5d0cde57 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -116,22 +116,11 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_FreeSurface", ExactSpelling = true)] public static extern void FreeSurface(IntPtr surface); - [SuppressUnmanagedCodeSecurity] - [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerName", ExactSpelling = true)] - static extern IntPtr GameControllerNameInternal(IntPtr gamecontroller); + #region GameContoller - /// - /// Return the name for an openend game controller instance. - /// - /// The name of the game controller name. - /// Pointer to a game controller instance returned by GameControllerOpen. - public static string GameControllerName(IntPtr gamecontroller) - { - unsafe - { - return new string((sbyte*)GameControllerNameInternal(gamecontroller)); - } - } + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerEventState", ExactSpelling = true)] + public static extern EventState GameControllerEventState(EventState state); [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetAxis", ExactSpelling = true)] @@ -177,6 +166,27 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetJoystick", ExactSpelling = true)] public static extern IntPtr GameControllerGetJoystick(IntPtr gamecontroller); + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetCurrentDisplayMode", ExactSpelling = true)] + public static extern int GetCurrentDisplayMode(int displayIndex, out DisplayMode mode); + + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerName", ExactSpelling = true)] + static extern IntPtr GameControllerNameInternal(IntPtr gamecontroller); + + /// + /// Return the name for an openend game controller instance. + /// + /// The name of the game controller name. + /// Pointer to a game controller instance returned by GameControllerOpen. + public static string GameControllerName(IntPtr gamecontroller) + { + unsafe + { + return new string((sbyte*)GameControllerNameInternal(gamecontroller)); + } + } + /// /// Opens a game controller for use. /// @@ -189,9 +199,7 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerOpen", ExactSpelling = true)] public static extern IntPtr GameControllerOpen(int joystick_index); - [SuppressUnmanagedCodeSecurity] - [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetCurrentDisplayMode", ExactSpelling = true)] - public static extern int GetCurrentDisplayMode(int displayIndex, out DisplayMode mode); + #endregion [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GetDisplayBounds", ExactSpelling = true)] @@ -280,6 +288,10 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickClose", ExactSpelling = true)] public static extern void JoystickClose(IntPtr joystick); + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickEventState", ExactSpelling = true)] + public static extern EventState JoystickEventState(EventState enabled); + [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickGetAxis", ExactSpelling = true)] public static extern short JoystickGetAxis(IntPtr joystick, int axis); @@ -545,6 +557,13 @@ namespace OpenTK.Platform.SDL2 ES = 0x0004 } + enum EventState + { + Query = -1, + Ignore = 0, + Enable = 1 + } + enum EventType { FIRSTEVENT = 0, diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index 023af9a2..f5df4654 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -55,6 +55,9 @@ namespace OpenTK.Platform.SDL2 { lock (SDL.Sync) { + SDL.GameControllerEventState(EventState.Enable); + SDL.JoystickEventState(EventState.Enable); + EventFilterDelegate = Marshal.GetFunctionPointerForDelegate(EventFilterDelegate_GCUnsafe); driver_handle = new IntPtr(count++); DriverHandles.Add(driver_handle, this); From 43ef78f222fa90185290989610d0107f3ed5cf40 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 17:09:20 +0100 Subject: [PATCH 126/154] [SDL2] Fix issue where changes to mutable struct were lost --- Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index e284cc59..c40562e5 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -47,8 +47,8 @@ namespace OpenTK.Platform.SDL2 class Sdl2GamePad { public IntPtr Handle { get; private set; } - public GamePadState State { get; set; } - public GamePadCapabilities Capabilities { get; set; } + public GamePadState State; + public GamePadCapabilities Capabilities; public Sdl2GamePad(IntPtr handle) { From 9c8a5f5028c299b228e05cad586919ca4db5ca59 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 17:15:49 +0100 Subject: [PATCH 127/154] [SDL2] Fixed GameControllerButton to Buttons translation --- .../Platform/SDL2/Sdl2JoystickDriver.cs | 57 ++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index c40562e5..70f08ca9 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -203,6 +203,61 @@ namespace OpenTK.Platform.SDL2 String.Format("[SDL] Unknown axis {0}", axis)); } } + + Buttons TranslateButton(GameControllerButton button) + { + switch (button) + { + case GameControllerButton.A: + return Buttons.A; + + case GameControllerButton.B: + return Buttons.B; + + case GameControllerButton.X: + return Buttons.X; + + case GameControllerButton.Y: + return Buttons.Y; + + case GameControllerButton.LEFTSHOULDER: + return Buttons.LeftShoulder; + + case GameControllerButton.RIGHTSHOULDER: + return Buttons.RightShoulder; + + case GameControllerButton.LEFTSTICK: + return Buttons.LeftStick; + + case GameControllerButton.RIGHTSTICK: + return Buttons.RightStick; + + case GameControllerButton.DPAD_UP: + return Buttons.DPadUp; + + case GameControllerButton.DPAD_DOWN: + return Buttons.DPadDown; + + case GameControllerButton.DPAD_LEFT: + return Buttons.DPadLeft; + + case GameControllerButton.DPAD_RIGHT: + return Buttons.DPadRight; + + case GameControllerButton.BACK: + return Buttons.Back; + + case GameControllerButton.START: + return Buttons.Start; + + case GameControllerButton.GUIDE: + return Buttons.BigButton; + + default: + Debug.Print("[SDL2] Unknown button {0}", button); + return 0; + } + } #endregion #region Public Members @@ -423,7 +478,7 @@ namespace OpenTK.Platform.SDL2 if (IsControllerInstanceValid(instance_id)) { int id = sdl_instanceid_to_controllers[instance_id]; - controllers[id].State.SetButton((Buttons)ev.Button, ev.State == State.Pressed); + controllers[id].State.SetButton(TranslateButton(ev.Button), ev.State == State.Pressed); } else { From d4348c50837157cc62d27ca37a5c80076f0ba325 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Mon, 30 Dec 2013 17:22:45 +0100 Subject: [PATCH 128/154] [SDL2] Fixed joystick/controller hotplugging support --- Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 70f08ca9..b0786d02 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -303,11 +303,13 @@ namespace OpenTK.Platform.SDL2 case EventType.JOYDEVICEREMOVED: if (IsJoystickInstanceValid(id)) { - int instance_id = sdl_instanceid_to_joysticks[id]; - sdl_instanceid_to_joysticks.Remove(id); + int instance_id = id; + int device_id = sdl_instanceid_to_joysticks[instance_id]; - JoystickDevice joystick = (JoystickDevice)joysticks[instance_id]; + JoystickDevice joystick = (JoystickDevice)joysticks[device_id]; joystick.Details.IsConnected = false; + + sdl_instanceid_to_joysticks.Remove(instance_id); } else { @@ -436,8 +438,11 @@ namespace OpenTK.Platform.SDL2 case EventType.CONTROLLERDEVICEREMOVED: if (IsControllerInstanceValid(id)) { - controllers[id].State.SetConnected(false); - sdl_instanceid_to_controllers.Remove(id); + int instance_id = id; + int device_id = sdl_instanceid_to_controllers[instance_id]; + + controllers[device_id].State.SetConnected(false); + sdl_instanceid_to_controllers.Remove(device_id); } else { From 7d4d116ce9efd280e4d21533f85998203c3221ad Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 31 Dec 2013 01:01:52 +0100 Subject: [PATCH 129/154] [Input] Renamed GamePadMapping to GamePadMap --- Source/OpenTK/Input/GamePadMap.cs | 148 ++++++++++++++++++++++++++ Source/OpenTK/Input/GamePadMapping.cs | 39 ------- Source/OpenTK/OpenTK.csproj | 2 +- 3 files changed, 149 insertions(+), 40 deletions(-) create mode 100644 Source/OpenTK/Input/GamePadMap.cs delete mode 100644 Source/OpenTK/Input/GamePadMapping.cs diff --git a/Source/OpenTK/Input/GamePadMap.cs b/Source/OpenTK/Input/GamePadMap.cs new file mode 100644 index 00000000..c67ca8c2 --- /dev/null +++ b/Source/OpenTK/Input/GamePadMap.cs @@ -0,0 +1,148 @@ +#region License +// +// GamePadMapping.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2013 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 System.Text; + +namespace OpenTK.Input +{ + enum MapType + { + Axis = 0, + Button = 1 + } + + class MapItem + { + MapType map_type; + Nullable map_button; + Nullable map_axis; + + public MapItem(JoystickAxis axis) + { + Type = MapType.Axis; + Axis = axis; + } + + public MapItem(JoystickButton button) + { + Type = MapType.Button; + Button = button; + } + + public MapType Type + { + get { return map_type; } + private set { map_type = value; } + } + + public Nullable Axis + { + get { return map_axis; } + private set { map_axis = value; } + } + + public Nullable Button + { + get { return map_button; } + private set { map_button = value; } + } + } + + class GamePadMap + { + static readonly GamePadMap default_map; + + MapItem a, b, x, y; + MapItem lshoulder, rshoulder; + MapItem lstick, rstick; + MapItem start, back; + MapItem home; + MapItem axis_lx, axis_ly; + MapItem axis_rx, axis_ry; + MapItem ltrigger, rtrigger; + MapItem dpad_u, dpad_d; + MapItem dpad_l, dpad_r; + + public MapItem A { get { return a; } set { a = value; } } + public MapItem B { get { return b; } set { b = value; } } + public MapItem X { get { return x; } set { x = value; } } + public MapItem Y { get { return y; } set { y = value; } } + public MapItem LeftShoulder { get { return lshoulder; } set { lshoulder = value; } } + public MapItem RightShoulder { get { return rshoulder; } set { rshoulder = value; } } + public MapItem LeftStick { get { return lstick; } set { lstick = value; } } + public MapItem RightStick { get { return rstick; } set { rstick = value; } } + public MapItem Start { get { return start; } set { start = value; } } + public MapItem Back { get { return back; } set { back = value; } } + public MapItem BigButton { get { return home; } set { home = value; } } + public MapItem LeftAxisX { get { return axis_lx; } set { axis_lx = value; } } + public MapItem LeftAxisY { get { return axis_ly; } set { axis_ly = value; } } + public MapItem RightAxisX { get { return axis_rx; } set { axis_rx = value; } } + public MapItem RightAxisY { get { return axis_ry; } set { axis_ry = value; } } + public MapItem LeftTrigger { get { return ltrigger; } set { ltrigger = value; } } + public MapItem RightTrigger { get { return rtrigger; } set { rtrigger = value; } } + public MapItem DPadUp { get { return dpad_u; } set { dpad_u = value; } } + public MapItem DPadDown { get { return dpad_d; } set { dpad_d = value; } } + public MapItem DPadLeft { get { return dpad_l; } set { dpad_l = value; } } + public MapItem DPadRight { get { return dpad_r; } set { dpad_r = value; } } + + static GamePadMap() + { + GamePadMap map = new GamePadMap(); + map.A = new MapItem(JoystickButton.Button0); + map.B = new MapItem(JoystickButton.Button1); + map.X = new MapItem(JoystickButton.Button2); + map.Y = new MapItem(JoystickButton.Button3); + map.LeftShoulder = new MapItem(JoystickButton.Button4); + map.RightShoulder = new MapItem(JoystickButton.Button5); + map.LeftStick = new MapItem(JoystickButton.Button6); + map.RightStick = new MapItem(JoystickButton.Button7); + map.Start = new MapItem(JoystickButton.Button8); + map.Back = new MapItem(JoystickButton.Button9); + map.BigButton = new MapItem(JoystickButton.Button10); + map.DPadUp = new MapItem(JoystickButton.Button11); + map.DPadDown = new MapItem(JoystickButton.Button12); + map.DPadLeft = new MapItem(JoystickButton.Button13); + map.DPadRight = new MapItem(JoystickButton.Button14); + map.LeftAxisX = new MapItem(JoystickAxis.Axis0); + map.LeftAxisY = new MapItem(JoystickAxis.Axis1); + map.RightAxisX = new MapItem(JoystickAxis.Axis2); + map.RightAxisY = new MapItem(JoystickAxis.Axis3); + map.LeftTrigger = new MapItem(JoystickAxis.Axis4); + map.RightTrigger = new MapItem(JoystickAxis.Axis5); + default_map = map; + } + + public static GamePadMap Default + { + get { return default_map; } + } + } +} diff --git a/Source/OpenTK/Input/GamePadMapping.cs b/Source/OpenTK/Input/GamePadMapping.cs deleted file mode 100644 index 9ddca29f..00000000 --- a/Source/OpenTK/Input/GamePadMapping.cs +++ /dev/null @@ -1,39 +0,0 @@ -#region License -// -// GamePadMapping.cs -// -// Author: -// Stefanos A. -// -// Copyright (c) 2006-2013 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 System.Text; - -namespace OpenTK.Input -{ - class GamePadMapping - { - } -} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index a378e483..af108d7a 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -133,7 +133,6 @@ - @@ -792,6 +791,7 @@ + From ef7f31099d61416ff5aafd6c9cd83ee3d5a3ffb4 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 31 Dec 2013 01:02:07 +0100 Subject: [PATCH 130/154] [Input] Removed unnecessary #region --- Source/OpenTK/Input/JoystickButton.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Source/OpenTK/Input/JoystickButton.cs b/Source/OpenTK/Input/JoystickButton.cs index cf3a9ca6..e8daf6ed 100644 --- a/Source/OpenTK/Input/JoystickButton.cs +++ b/Source/OpenTK/Input/JoystickButton.cs @@ -33,8 +33,6 @@ using System.Text; namespace OpenTK.Input { - #region JoystickButton - /// /// Defines available JoystickDevice buttons. /// @@ -73,6 +71,4 @@ namespace OpenTK.Input /// The sixteenth button of the JoystickDevice. Button15, } - - #endregion } From 1687518ef5f419a916cfb8b582a512912c24b41d Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 31 Dec 2013 11:46:40 +0100 Subject: [PATCH 131/154] [SDL2] Add compile-time check for SDL2 GameController vs MappedGamePadDriver --- .../OpenTK/Platform/SDL2/Sdl2InputDriver.cs | 2 + .../Platform/SDL2/Sdl2JoystickDriver.cs | 40 ++++++++++++++++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs index f5df4654..5e88fd6d 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2InputDriver.cs @@ -126,6 +126,7 @@ namespace OpenTK.Platform.SDL2 driver.joystick_driver.ProcessJoystickEvent(ev.JoyHat); break; +#if USE_SDL2_GAMECONTROLLER case EventType.CONTROLLERDEVICEADDED: case EventType.CONTROLLERDEVICEREMOVED: driver.joystick_driver.ProcessControllerEvent(ev.ControllerDevice); @@ -139,6 +140,7 @@ namespace OpenTK.Platform.SDL2 case EventType.CONTROLLERBUTTONUP: driver.joystick_driver.ProcessControllerEvent(ev.ControllerButton); break; +#endif } } } diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index b0786d02..01c72b82 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -35,6 +35,8 @@ namespace OpenTK.Platform.SDL2 class Sdl2JoystickDriver : IJoystickDriver, IJoystickDriver2, IGamePadDriver, IDisposable { const float RangeMultiplier = 1.0f / 32768.0f; + readonly MappedGamePadDriver gamepad_driver = new MappedGamePadDriver(); + bool disposed; struct Sdl2JoystickDetails { @@ -44,6 +46,15 @@ namespace OpenTK.Platform.SDL2 public bool IsConnected { get; set; } } + // For IJoystickDriver2 implementation + int last_joystick_instance = 0; + readonly List joysticks = new List(4); + readonly Dictionary sdl_instanceid_to_joysticks = new Dictionary(); + + // For IJoystickDriver implementation + IList joysticks_readonly; + +#if USE_SDL2_GAMECONTROLLER class Sdl2GamePad { public IntPtr Handle { get; private set; } @@ -56,16 +67,11 @@ namespace OpenTK.Platform.SDL2 } } - int last_joystick_instance = 0; int last_controllers_instance = 0; - - readonly List joysticks = new List(4); - readonly Dictionary sdl_instanceid_to_joysticks = new Dictionary(); readonly List controllers = new List(4); readonly Dictionary sdl_instanceid_to_controllers = new Dictionary(); +#endif - IList joysticks_readonly; - bool disposed; public Sdl2JoystickDriver() { @@ -119,6 +125,7 @@ namespace OpenTK.Platform.SDL2 return sdl_instanceid_to_joysticks.ContainsKey(instance_id); } +#if USE_SDL2_GAMECONTROLLER bool IsControllerValid(int id) { return id >= 0 && id < controllers.Count; @@ -258,6 +265,8 @@ namespace OpenTK.Platform.SDL2 return 0; } } +#endif + #endregion #region Public Members @@ -380,6 +389,7 @@ namespace OpenTK.Platform.SDL2 } } +#if USE_SDL2_GAMECONTROLLER public void ProcessControllerEvent(ControllerDeviceEvent ev) { int id = ev.Which; @@ -490,6 +500,7 @@ namespace OpenTK.Platform.SDL2 Debug.Print("[SDL2] Invalid game controller instance {0} in {1}", instance_id, ev.Type); } } +#endif #endregion @@ -512,6 +523,7 @@ namespace OpenTK.Platform.SDL2 #region IGamePadDriver Members +#if USE_SDL2_GAMECONTOLLER public GamePadCapabilities GetCapabilities(int index) { if (IsControllerValid(index)) @@ -534,6 +546,22 @@ namespace OpenTK.Platform.SDL2 { return String.Empty; } +#else + public GamePadCapabilities GetCapabilities(int index) + { + return gamepad_driver.GetCapabilities(index); + } + + public GamePadState GetState(int index) + { + return gamepad_driver.GetState(index); + } + + public string GetName(int index) + { + return gamepad_driver.GetName(index); + } +#endif #endregion From cd143af60a7ff875fc3ebf38d6d2b35ed0b12adf Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 31 Dec 2013 14:08:28 +0100 Subject: [PATCH 132/154] [SDL2] Added JoystickGetGUID method --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 5d0cde57..8ad25480 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -300,6 +300,10 @@ namespace OpenTK.Platform.SDL2 [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickGetButton", ExactSpelling = true)] public static extern byte JoystickGetButton(IntPtr joystick, int button); + [SuppressUnmanagedCodeSecurity] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickGetGuid", ExactSpelling = true)] + public static extern JoystickGuid JoystickGetGUID(IntPtr joystick); + [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickName", ExactSpelling = true)] static extern IntPtr JoystickNameInternal(IntPtr joystick); @@ -1404,6 +1408,26 @@ namespace OpenTK.Platform.SDL2 byte padding2; } + struct JoystickGuid + { + unsafe fixed byte data[16]; + + public Guid ToGuid() + { + byte[] bytes = new byte[16]; + + unsafe + { + fixed (byte* pdata = data) + { + Marshal.Copy(new IntPtr(pdata), bytes, 0, bytes.Length); + } + } + + return new Guid(bytes); + } + } + struct KeyboardEvent { public EventType Type; From b9a8e365dea405675ec79caa6e5089ae0010e535 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Tue, 31 Dec 2013 14:09:17 +0100 Subject: [PATCH 133/154] [Input] Added IJoystickDriver2.GetGuid() API --- Source/OpenTK/Input/IJoystickDriver2.cs | 1 + Source/OpenTK/Input/Joystick.cs | 5 +++++ Source/OpenTK/Platform/MacOS/HIDInput.cs | 5 +++++ .../OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs | 17 ++++++++++++++++- Source/OpenTK/Platform/Windows/WinMMJoystick.cs | 12 ++++++++++++ Source/OpenTK/Platform/X11/X11Joystick.cs | 5 +++++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Input/IJoystickDriver2.cs b/Source/OpenTK/Input/IJoystickDriver2.cs index 1359d1de..8e536aaf 100644 --- a/Source/OpenTK/Input/IJoystickDriver2.cs +++ b/Source/OpenTK/Input/IJoystickDriver2.cs @@ -37,5 +37,6 @@ namespace OpenTK.Input { JoystickState GetState(int index); JoystickCapabilities GetCapabilities(int index); + Guid GetGuid(int index); } } diff --git a/Source/OpenTK/Input/Joystick.cs b/Source/OpenTK/Input/Joystick.cs index 378b11f4..2b10cfb9 100644 --- a/Source/OpenTK/Input/Joystick.cs +++ b/Source/OpenTK/Input/Joystick.cs @@ -48,6 +48,11 @@ namespace OpenTK.Input return implementation.GetState(index); } + internal static Guid GetGuid(int index) + { + return implementation.GetGuid(index); + } + //public string GetName(int index) //{ // return implementation.GetName(index); diff --git a/Source/OpenTK/Platform/MacOS/HIDInput.cs b/Source/OpenTK/Platform/MacOS/HIDInput.cs index 0967afef..9090e703 100755 --- a/Source/OpenTK/Platform/MacOS/HIDInput.cs +++ b/Source/OpenTK/Platform/MacOS/HIDInput.cs @@ -381,6 +381,11 @@ namespace OpenTK.Platform.MacOS return new JoystickCapabilities(); } + Guid IJoystickDriver2.GetGuid(int index) + { + return new Guid(); + } + #endregion #region NativeMethods diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 01c72b82..25b6b253 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -38,9 +38,10 @@ namespace OpenTK.Platform.SDL2 readonly MappedGamePadDriver gamepad_driver = new MappedGamePadDriver(); bool disposed; - struct Sdl2JoystickDetails + class Sdl2JoystickDetails { public IntPtr Handle { get; set; } + public Guid Guid { get; set; } public int HatCount { get; set; } public int BallCount { get; set; } public bool IsConnected { get; set; } @@ -99,6 +100,7 @@ namespace OpenTK.Platform.SDL2 joystick = new JoystickDevice(id, num_axes, num_buttons); joystick.Description = SDL.JoystickName(handle); joystick.Details.Handle = handle; + joystick.Details.Guid = SDL.JoystickGetGUID(handle).ToGuid(); joystick.Details.HatCount = num_hats; joystick.Details.BallCount = num_balls; @@ -606,6 +608,19 @@ namespace OpenTK.Platform.SDL2 return new JoystickCapabilities(); } + Guid IJoystickDriver2.GetGuid(int index) + { + Guid guid = new Guid(); + if (IsJoystickValid(index)) + { + JoystickDevice joystick = + (JoystickDevice)joysticks[index]; + + return joystick.Details.Guid; + } + return guid; + } + #endregion #region IDisposable Members diff --git a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs index fa84aba1..313abdd9 100644 --- a/Source/OpenTK/Platform/Windows/WinMMJoystick.cs +++ b/Source/OpenTK/Platform/Windows/WinMMJoystick.cs @@ -333,6 +333,18 @@ namespace OpenTK.Platform.Windows return state; } + public Guid GetGuid(int index) + { + Guid guid = new Guid(); + + if (IsValid(index)) + { + // Todo: implement WinMM Guid retrieval + } + + return guid; + } + #endregion #region IDisposable diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs index 36fac9f2..5f76dd54 100644 --- a/Source/OpenTK/Platform/X11/X11Joystick.cs +++ b/Source/OpenTK/Platform/X11/X11Joystick.cs @@ -290,6 +290,11 @@ namespace OpenTK.Platform.X11 throw new NotImplementedException(); } + Guid IJoystickDriver2.GetGuid(int index) + { + throw new NotImplementedException(); + } + #endregion } } From 5e75fac056286b1ff742205a7e8535e14f4846e1 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 01:06:47 +0100 Subject: [PATCH 134/154] [Input] Added configuration db for GamePads The database is based on the SDL bindings found at https://hg.libsdl.org/SDL/file/b744b3f8754b/src/joystick/SDL_gamecontrol lerdb.h --- .../Input/GamePadConfigurationDatabase.cs | 110 ++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 1 + 2 files changed, 111 insertions(+) create mode 100644 Source/OpenTK/Input/GamePadConfigurationDatabase.cs diff --git a/Source/OpenTK/Input/GamePadConfigurationDatabase.cs b/Source/OpenTK/Input/GamePadConfigurationDatabase.cs new file mode 100644 index 00000000..95205993 --- /dev/null +++ b/Source/OpenTK/Input/GamePadConfigurationDatabase.cs @@ -0,0 +1,110 @@ +#region License +// +// GamePadConfigurationDatabase.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +#endregion + +using System; +using System.Collections.Generic; + +namespace OpenTK.Input +{ + static class GamePadConfigurationDatabase + { + internal static readonly Dictionary Configurations = new Dictionary(); + + static GamePadConfigurationDatabase() + { + // Configuration database copied from SDL + + #region License + // Simple DirectMedia Layer + // Copyright (C) 1997-2013 Sam Lantinga + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + #endregion + + // Default configuration, used when no suitable configuration is available + Add("00000000000000000000000000000000,Unknown Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); + + // Windows + Add("341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); + Add("ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,"); + Add("6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); + Add("6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); // Guide button doesn't seem to be sent in DInput mode. + Add("88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,"); + Add("4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,"); + Add("25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,"); + Add("xinput00000000000000000000000000,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,"); + + // Mac OS X + Add("0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,"); + Add("6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); /* Guide button doesn't seem to be sent in DInput mode. */ + Add("6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); + Add("6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,"); + Add("6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); /* This includes F710 in DInput mode and the "Logitech Cordless RumblePad 2"); at the very least. */ + Add("4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,"); + Add("5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,"); + + // Linux + Add("0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,"); + Add("03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,"); + Add("030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); + Add("030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); + Add("030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); + Add("030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); /* Guide button doesn't seem to be sent in DInput mode. */ + Add("030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); + Add("030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,"); + Add("03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); + Add("030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); + Add("030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); + Add("030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); + Add("030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); + } + + static void Add(string config) + { + Configurations.Add( + new Guid(config.Substring(0, 32)), + config); + } + } +} + diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index af108d7a..ec3d8aff 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -792,6 +792,7 @@ + From f0fbb26efed299b5c01ee4eb87f0413380023e1c Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 01:07:21 +0100 Subject: [PATCH 135/154] [Input] Added ability to parse SDL configuration db strings --- Source/OpenTK/Input/GamePadMap.cs | 195 +++++++++++++++++++++++++++++- 1 file changed, 193 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Input/GamePadMap.cs b/Source/OpenTK/Input/GamePadMap.cs index c67ca8c2..c9cfaf1e 100644 --- a/Source/OpenTK/Input/GamePadMap.cs +++ b/Source/OpenTK/Input/GamePadMap.cs @@ -29,14 +29,16 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Text; namespace OpenTK.Input { enum MapType { - Axis = 0, - Button = 1 + Unmapped = 0, + Axis, + Button } class MapItem @@ -45,6 +47,10 @@ namespace OpenTK.Input Nullable map_button; Nullable map_axis; + public MapItem() + { + } + public MapItem(JoystickAxis axis) { Type = MapType.Axis; @@ -80,6 +86,8 @@ namespace OpenTK.Input { static readonly GamePadMap default_map; + Guid guid; + string name; MapItem a, b, x, y; MapItem lshoulder, rshoulder; MapItem lstick, rstick; @@ -91,6 +99,8 @@ namespace OpenTK.Input MapItem dpad_u, dpad_d; MapItem dpad_l, dpad_r; + Guid Guid { get { return guid; } set { guid = value; } } + string Name { get { return name; } set { name = value; } } public MapItem A { get { return a; } set { a = value; } } public MapItem B { get { return b; } set { b = value; } } public MapItem X { get { return x; } set { x = value; } } @@ -113,6 +123,14 @@ namespace OpenTK.Input public MapItem DPadLeft { get { return dpad_l; } set { dpad_l = value; } } public MapItem DPadRight { get { return dpad_r; } set { dpad_r = value; } } + public GamePadMap() + { + } + + public GamePadMap(string configuration) + { + } + static GamePadMap() { GamePadMap map = new GamePadMap(); @@ -144,5 +162,178 @@ namespace OpenTK.Input { get { return default_map; } } + + public static GamePadMap GetConfiguration(Guid guid) + { + GamePadMap map = GamePadMap.Default; + if (GamePadConfigurationDatabase.Configurations.ContainsKey(guid)) + { + map = ParseConfiguration(GamePadConfigurationDatabase.Configurations[guid]); + } + return map; + } + + // Parses a GamePad configuration string. The string + // follows the rules for SDL2 GameController, outlined here: + // http://wiki.libsdl.org/SDL_GameControllerAddMapping + static GamePadMap ParseConfiguration(string configuration) + { + if (String.IsNullOrEmpty(configuration)) + { + throw new ArgumentNullException(); + } + + // The mapping string has the format "GUID,name,config" + // - GUID is a unigue identifier returned by Joystick.GetGuid() + // - name is a human-readable name for the controller + // - config is a comma-separated list of configurations as follows: + // - [gamepad axis or button name]:[joystick axis, button or hat number] + string[] items = configuration.Split(','); + if (items.Length < 3) + { + throw new ArgumentException(); + } + + GamePadMap map = new GamePadMap(); + map.Guid = new Guid(items[0]); + map.Name = items[1]; + for (int i = 2; i < items.Length; i++) + { + string[] config = items[i].Split(':'); + MapItem map_item = ParseItem(config[1]); + switch (config[0]) + { + case "a": + map.A = map_item; + break; + + case "b": + map.B = map_item; + break; + + case "x": + map.X = map_item; + break; + + case "y": + map.Y = map_item; + break; + + case "start": + map.Start = map_item; + break; + + case "back": + map.Back = map_item; + break; + + case "guide": + map.BigButton = map_item; + break; + + case "dpup": + map.DPadUp = map_item; + break; + + case "dpdown": + map.DPadDown = map_item; + break; + + case "dpleft": + map.DPadLeft = map_item; + break; + + case "dpright": + map.DPadRight = map_item; + break; + + case "leftshoulder": + map.LeftShoulder = map_item; + break; + + case "rightshoulder": + map.RightShoulder = map_item; + break; + + case "leftstick": + map.LeftStick = map_item; + break; + + case "rightstick": + map.RightStick = map_item; + break; + + case "leftx": + map.LeftAxisX = map_item; + break; + + case "lefty": + map.LeftAxisY = map_item; + break; + + case "rightx": + map.RightAxisX = map_item; + break; + + case "righty": + map.RightAxisY = map_item; + break; + + case "lefttrigger": + map.LeftTrigger = map_item; + break; + + case "righttrigger": + map.RightTrigger = map_item; + break; + + default: + Debug.Print("[Input] Invalid GamePad configuration name: {0}", items[i]); + break; + } + } + + return map; + } + + static MapItem ParseItem(string item) + { + if (String.IsNullOrEmpty(item)) + { + return new MapItem(); + } + + switch (item[0]) + { + case 'a': + return new MapItem(ParseAxis(item)); + + case 'b': + return new MapItem(ParseButton(item)); + + case 'h': + throw new NotImplementedException(); + //return new MapItem(ParseHat(item)); + + default: + throw new InvalidOperationException("[Input] Invalid GamePad configuration value"); + } + } + + static JoystickAxis ParseAxis(string item) + { + // item is in the format "a#" where # a zero-based integer number + JoystickAxis axis = JoystickAxis.Axis0; + int id = Int32.Parse(item.Substring(1)); + return axis + id; + } + + static JoystickButton ParseButton(string item) + { + // item is in the format "b#" where # a zero-based integer nubmer + JoystickButton button = JoystickButton.Button0; + int id = Int32.Parse(item.Substring(1)); + return button + id; + } } } From a0dad7f6981cdb57b2b6632e8c640239a8356883 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 01:13:20 +0100 Subject: [PATCH 136/154] [Input] Implemented MappedGamePadDriver.GetCapabilities() --- Source/OpenTK/Platform/MappedGamePadDriver.cs | 76 ++++++++++++++++++- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs index 346be196..dbac6149 100644 --- a/Source/OpenTK/Platform/MappedGamePadDriver.cs +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -52,13 +52,18 @@ namespace OpenTK.Platform /// class MappedGamePadDriver : IGamePadDriver { + readonly Dictionary configurations = + new Dictionary(); + public GamePadState GetState(int index) { JoystickState joy = Joystick.GetState(index); GamePadState pad = new GamePadState(); if (joy.IsConnected) { - GamePadMapping mapping = new GamePadMapping();//GamePadMapping.Lookup() + GamePadMap map = GetConfiguration(Joystick.GetGuid(index)); + + // Todo: implement mapping } return pad; @@ -67,10 +72,19 @@ namespace OpenTK.Platform public GamePadCapabilities GetCapabilities(int index) { JoystickCapabilities joy = Joystick.GetCapabilities(index); - GamePadCapabilities pad = new GamePadCapabilities(); + GamePadCapabilities pad; if (joy.IsConnected) { - // Todo: implement mapping + GamePadMap map = GetConfiguration(Joystick.GetGuid(index)); + pad = new GamePadCapabilities( + GamePadType.GamePad, // Todo: detect different types + TranslateAxes(map), + TranslateButtons(map), + true); + } + else + { + pad = new GamePadCapabilities(); } return pad; } @@ -79,5 +93,61 @@ namespace OpenTK.Platform { throw new NotImplementedException(); } + + #region Private Members + + GamePadMap GetConfiguration(Guid guid) + { + if (!configurations.ContainsKey(guid)) + { + GamePadMap map = GamePadMap.GetConfiguration(guid); + configurations.Add(guid, map); + } + return configurations[guid]; + } + + bool IsMapped(MapItem item) + { + return item.Type != MapType.Unmapped; + } + + GamePadAxes TranslateAxes(GamePadMap map) + { + GamePadAxes axes = 0; + axes |= IsMapped(map.LeftAxisX) ? GamePadAxes.LeftX : 0; + axes |= IsMapped(map.LeftAxisY) ? GamePadAxes.LeftY : 0; + axes |= IsMapped(map.RightAxisX) ? GamePadAxes.RightX : 0; + axes |= IsMapped(map.RightAxisY) ? GamePadAxes.RightY : 0; + axes |= IsMapped(map.LeftTrigger) ? GamePadAxes.LeftTrigger : 0; + axes |= IsMapped(map.RightTrigger) ? GamePadAxes.RightTrigger : 0; + return axes; + } + + Buttons TranslateButtons(GamePadMap map) + { + Buttons buttons = 0; + buttons |= IsMapped(map.A) ? Buttons.A : 0; + buttons |= IsMapped(map.B) ? Buttons.B : 0; + buttons |= IsMapped(map.X) ? Buttons.X : 0; + buttons |= IsMapped(map.Y) ? Buttons.Y : 0; + buttons |= IsMapped(map.Start) ? Buttons.Start : 0; + buttons |= IsMapped(map.Back) ? Buttons.Back : 0; + buttons |= IsMapped(map.BigButton) ? Buttons.BigButton : 0; + buttons |= IsMapped(map.LeftShoulder) ? Buttons.LeftShoulder : 0; + buttons |= IsMapped(map.RightShoulder) ? Buttons.RightShoulder : 0; + buttons |= IsMapped(map.LeftStick) ? Buttons.LeftStick : 0; + buttons |= IsMapped(map.RightStick) ? Buttons.RightStick : 0; + return buttons; + } + +// bool TranslateDPad(GamePadMap map) +// { +// pad.HasDPadDownButton = IsMapped(map.DPadDown); +// pad.HasDPadUpButton = IsMapped(map.DPadUp); +// pad.HasDPadLeftButton = IsMapped(map.DPadLeft); +// pad.HasDPadRightButton = IsMapped(map.DPadRight); +// } + + #endregion } } From b056a50e73c8744a23c899d9c6840a88babbd46c Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 01:33:08 +0100 Subject: [PATCH 137/154] [Input] Added xml documentation for GamePadCapabilities --- Source/OpenTK/Input/GamePadCapabilities.cs | 170 ++++++++++++++++++++- 1 file changed, 164 insertions(+), 6 deletions(-) diff --git a/Source/OpenTK/Input/GamePadCapabilities.cs b/Source/OpenTK/Input/GamePadCapabilities.cs index 7fbe8055..269081e8 100644 --- a/Source/OpenTK/Input/GamePadCapabilities.cs +++ b/Source/OpenTK/Input/GamePadCapabilities.cs @@ -31,7 +31,9 @@ using System; namespace OpenTK.Input { - + /// + /// Describes the capabilities of a GamePad input device. + /// public struct GamePadCapabilities : IEquatable { Buttons buttons; @@ -54,146 +56,285 @@ namespace OpenTK.Input #region Public Members + /// + /// Gets a value describing the type of a input device. + /// This value depends on the connected device and the drivers in use. If IsConnected + /// is false, then this value will be GamePadType.Unknown. + /// + /// The GamePadType of the connected input device. public GamePadType GamePadType { get { return (GamePadType)gamepad_type; } } + /// + /// Gets a value describing whether this GamePad has + /// an up digital pad button. + /// + /// true if this instance has an up digital pad button; otherwise, false. public bool HasDPadUpButton { get { return (buttons & Buttons.DPadUp) != 0; } } - public bool HasDPadLeftButton - { - get { return (buttons & Buttons.DPadLeft) != 0; } - } - + /// + /// Gets a value describing whether this GamePad has + /// a down digital pad button. + /// + /// true if this instance has a down digital pad button; otherwise, false. public bool HasDPadDownButton { get { return (buttons & Buttons.DPadDown) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a left digital pad button. + /// + /// true if this instance has a left digital pad button; otherwise, false. + public bool HasDPadLeftButton + { + get { return (buttons & Buttons.DPadLeft) != 0; } + } + + /// + /// Gets a value describing whether this GamePad has + /// a right digital pad button. + /// + /// true if this instance has a right digital pad button; otherwise, false. public bool HasDPadRightButton { get { return (buttons & Buttons.DPadRight) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// an A button. + /// + /// true if this instance has an A button; otherwise, false. public bool HasAButton { get { return (buttons & Buttons.A) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a B button. + /// + /// true if this instance has a B button; otherwise, false. public bool HasBButton { get { return (buttons & Buttons.B) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a X button. + /// + /// true if this instance has a X button; otherwise, false. public bool HasXButton { get { return (buttons & Buttons.X) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a Y button. + /// + /// true if this instance has a Y button; otherwise, false. public bool HasYButton { get { return (buttons & Buttons.Y) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a left stick button. + /// + /// true if this instance has a left stick button; otherwise, false. public bool HasLeftStickButton { get { return (buttons & Buttons.LeftStick) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a right stick button. + /// + /// true if this instance has a right stick button; otherwise, false. public bool HasRightStickButton { get { return (buttons & Buttons.RightStick) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a left shoulder button. + /// + /// true if this instance has a left shoulder button; otherwise, false. public bool HasLeftShoulderButton { get { return (buttons & Buttons.LeftShoulder) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a right shoulder button. + /// + /// true if this instance has a right shoulder button; otherwise, false. public bool HasRightShoulderButton { get { return (buttons & Buttons.RightShoulder) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a back button. + /// + /// true if this instance has a back button; otherwise, false. public bool HasBackButton { get { return (buttons & Buttons.Back) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a big button. (also known as "guide" or "home" button). + /// + /// true if this instance has a big button; otherwise, false. public bool HasBigButton { get { return (buttons & Buttons.BigButton) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a start button. + /// + /// true if this instance has a start button; otherwise, false. public bool HasStartButton { get { return (buttons & Buttons.Start) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a left thumbstick with a x-axis. + /// + /// true if this instance has a left thumbstick with a x-axis; otherwise, false. public bool HasLeftXThumbStick { get { return (axes & GamePadAxes.LeftX) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a left thumbstick with a y-axis. + /// + /// true if this instance has a left thumbstick with a y-axis; otherwise, false. public bool HasLeftYThumbStick { get { return (axes & GamePadAxes.LeftY) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a right thumbstick with a x-axis. + /// + /// true if this instance has a right thumbstick with a x-axis; otherwise, false. public bool HasRightXThumbStick { get { return (axes & GamePadAxes.RightX) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a right thumbstick with a y-axis. + /// + /// true if this instance has a right thumbstick with a y-axis; otherwise, false. public bool HasRightYThumbStick { get { return (axes & GamePadAxes.RightY) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a left trigger. + /// + /// true if this instance has a left trigger; otherwise, false. public bool HasLeftTrigger { get { return (axes & GamePadAxes.LeftTrigger) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a right trigger. + /// + /// true if this instance has a right trigger; otherwise, false. public bool HasRightTrigger { get { return (axes & GamePadAxes.RightTrigger) != 0; } } + /// + /// Gets a value describing whether this GamePad has + /// a low-frequency vibration motor. + /// + /// true if this instance has a low-frequency vibration motor; otherwise, false. public bool HasLeftVibrationMotor { get { return false; } } + /// + /// Gets a value describing whether this GamePad has + /// a high-frequency vibration motor. + /// + /// true if this instance has a high frequency vibration motor; otherwise, false. public bool HasRightVibrationMotor { get { return false; } } + /// + /// Gets a value describing whether this GamePad has + /// a microphone input. + /// + /// true if this instance has a microphone input; otherwise, false. public bool HasVoiceSupport { get { return false; } } + /// + /// Gets a value describing whether this GamePad is + /// currently connected. + /// + /// true if this instance is currently connected; otherwise, false. public bool IsConnected { get { return is_connected; } } + /// A structure to test for equality. + /// A structure to test for equality. public static bool operator ==(GamePadCapabilities left, GamePadCapabilities right) { return left.Equals(right); } + /// A structure to test for inequality. + /// A structure to test for inequality. public static bool operator !=(GamePadCapabilities left, GamePadCapabilities right) { return !left.Equals(right); } + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { return String.Format( @@ -204,6 +345,11 @@ namespace OpenTK.Input IsConnected); } + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. public override int GetHashCode() { return @@ -212,6 +358,12 @@ namespace OpenTK.Input gamepad_type.GetHashCode(); } + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals(object obj) { return @@ -223,6 +375,12 @@ namespace OpenTK.Input #region IEquatable Members + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals(GamePadCapabilities other) { return From c2c76f2ab2376351f81c75943e62de5dbf64ee6f Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 01:33:57 +0100 Subject: [PATCH 138/154] [Input] Made the Name property public We can use the name property to implement a hypothetical GamePad.GetName() method in the future. --- Source/OpenTK/Input/GamePadMap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OpenTK/Input/GamePadMap.cs b/Source/OpenTK/Input/GamePadMap.cs index c9cfaf1e..cc96f79e 100644 --- a/Source/OpenTK/Input/GamePadMap.cs +++ b/Source/OpenTK/Input/GamePadMap.cs @@ -100,7 +100,7 @@ namespace OpenTK.Input MapItem dpad_l, dpad_r; Guid Guid { get { return guid; } set { guid = value; } } - string Name { get { return name; } set { name = value; } } + public string Name { get { return name; } set { name = value; } } public MapItem A { get { return a; } set { a = value; } } public MapItem B { get { return b; } set { b = value; } } public MapItem X { get { return x; } set { x = value; } } From dc1ffab78dbd7a0a23a1aecaf04f1e504c565c92 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 01:34:21 +0100 Subject: [PATCH 139/154] [Input] Implemented IGamePadDriver.GetName() --- Source/OpenTK/Platform/MappedGamePadDriver.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs index dbac6149..8240d74c 100644 --- a/Source/OpenTK/Platform/MappedGamePadDriver.cs +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -91,7 +91,14 @@ namespace OpenTK.Platform public string GetName(int index) { - throw new NotImplementedException(); + JoystickCapabilities joy = Joystick.GetCapabilities(index); + string name = String.Empty; + if (joy.IsConnected) + { + GamePadMap map = GetConfiguration(Joystick.GetGuid(index)); + name = map.Name; + } + return name; } #region Private Members From fb57a9062d9dfbe2b2d1a54cd0fafb6bd45838b7 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 01:38:12 +0100 Subject: [PATCH 140/154] [Input] Renamed GamePadMap to GamePadConfiguration --- ...{GamePadMap.cs => GamePadConfiguration.cs} | 184 +++++++----------- .../OpenTK/Input/GamePadConfigurationItem.cs | 81 ++++++++ Source/OpenTK/OpenTK.csproj | 3 +- Source/OpenTK/Platform/MappedGamePadDriver.cs | 22 +-- 4 files changed, 162 insertions(+), 128 deletions(-) rename Source/OpenTK/Input/{GamePadMap.cs => GamePadConfiguration.cs} (56%) create mode 100644 Source/OpenTK/Input/GamePadConfigurationItem.cs diff --git a/Source/OpenTK/Input/GamePadMap.cs b/Source/OpenTK/Input/GamePadConfiguration.cs similarity index 56% rename from Source/OpenTK/Input/GamePadMap.cs rename to Source/OpenTK/Input/GamePadConfiguration.cs index cc96f79e..887ba6a1 100644 --- a/Source/OpenTK/Input/GamePadMap.cs +++ b/Source/OpenTK/Input/GamePadConfiguration.cs @@ -34,138 +34,90 @@ using System.Text; namespace OpenTK.Input { - enum MapType + class GamePadConfiguration { - Unmapped = 0, - Axis, - Button - } - - class MapItem - { - MapType map_type; - Nullable map_button; - Nullable map_axis; - - public MapItem() - { - } - - public MapItem(JoystickAxis axis) - { - Type = MapType.Axis; - Axis = axis; - } - - public MapItem(JoystickButton button) - { - Type = MapType.Button; - Button = button; - } - - public MapType Type - { - get { return map_type; } - private set { map_type = value; } - } - - public Nullable Axis - { - get { return map_axis; } - private set { map_axis = value; } - } - - public Nullable Button - { - get { return map_button; } - private set { map_button = value; } - } - } - - class GamePadMap - { - static readonly GamePadMap default_map; + static readonly GamePadConfiguration default_map; Guid guid; string name; - MapItem a, b, x, y; - MapItem lshoulder, rshoulder; - MapItem lstick, rstick; - MapItem start, back; - MapItem home; - MapItem axis_lx, axis_ly; - MapItem axis_rx, axis_ry; - MapItem ltrigger, rtrigger; - MapItem dpad_u, dpad_d; - MapItem dpad_l, dpad_r; + GamePadConfigurationItem a, b, x, y; + GamePadConfigurationItem lshoulder, rshoulder; + GamePadConfigurationItem lstick, rstick; + GamePadConfigurationItem start, back; + GamePadConfigurationItem home; + GamePadConfigurationItem axis_lx, axis_ly; + GamePadConfigurationItem axis_rx, axis_ry; + GamePadConfigurationItem ltrigger, rtrigger; + GamePadConfigurationItem dpad_u, dpad_d; + GamePadConfigurationItem dpad_l, dpad_r; Guid Guid { get { return guid; } set { guid = value; } } public string Name { get { return name; } set { name = value; } } - public MapItem A { get { return a; } set { a = value; } } - public MapItem B { get { return b; } set { b = value; } } - public MapItem X { get { return x; } set { x = value; } } - public MapItem Y { get { return y; } set { y = value; } } - public MapItem LeftShoulder { get { return lshoulder; } set { lshoulder = value; } } - public MapItem RightShoulder { get { return rshoulder; } set { rshoulder = value; } } - public MapItem LeftStick { get { return lstick; } set { lstick = value; } } - public MapItem RightStick { get { return rstick; } set { rstick = value; } } - public MapItem Start { get { return start; } set { start = value; } } - public MapItem Back { get { return back; } set { back = value; } } - public MapItem BigButton { get { return home; } set { home = value; } } - public MapItem LeftAxisX { get { return axis_lx; } set { axis_lx = value; } } - public MapItem LeftAxisY { get { return axis_ly; } set { axis_ly = value; } } - public MapItem RightAxisX { get { return axis_rx; } set { axis_rx = value; } } - public MapItem RightAxisY { get { return axis_ry; } set { axis_ry = value; } } - public MapItem LeftTrigger { get { return ltrigger; } set { ltrigger = value; } } - public MapItem RightTrigger { get { return rtrigger; } set { rtrigger = value; } } - public MapItem DPadUp { get { return dpad_u; } set { dpad_u = value; } } - public MapItem DPadDown { get { return dpad_d; } set { dpad_d = value; } } - public MapItem DPadLeft { get { return dpad_l; } set { dpad_l = value; } } - public MapItem DPadRight { get { return dpad_r; } set { dpad_r = value; } } + public GamePadConfigurationItem A { get { return a; } set { a = value; } } + public GamePadConfigurationItem B { get { return b; } set { b = value; } } + public GamePadConfigurationItem X { get { return x; } set { x = value; } } + public GamePadConfigurationItem Y { get { return y; } set { y = value; } } + public GamePadConfigurationItem LeftShoulder { get { return lshoulder; } set { lshoulder = value; } } + public GamePadConfigurationItem RightShoulder { get { return rshoulder; } set { rshoulder = value; } } + public GamePadConfigurationItem LeftStick { get { return lstick; } set { lstick = value; } } + public GamePadConfigurationItem RightStick { get { return rstick; } set { rstick = value; } } + public GamePadConfigurationItem Start { get { return start; } set { start = value; } } + public GamePadConfigurationItem Back { get { return back; } set { back = value; } } + public GamePadConfigurationItem BigButton { get { return home; } set { home = value; } } + public GamePadConfigurationItem LeftAxisX { get { return axis_lx; } set { axis_lx = value; } } + public GamePadConfigurationItem LeftAxisY { get { return axis_ly; } set { axis_ly = value; } } + public GamePadConfigurationItem RightAxisX { get { return axis_rx; } set { axis_rx = value; } } + public GamePadConfigurationItem RightAxisY { get { return axis_ry; } set { axis_ry = value; } } + public GamePadConfigurationItem LeftTrigger { get { return ltrigger; } set { ltrigger = value; } } + public GamePadConfigurationItem RightTrigger { get { return rtrigger; } set { rtrigger = value; } } + public GamePadConfigurationItem DPadUp { get { return dpad_u; } set { dpad_u = value; } } + public GamePadConfigurationItem DPadDown { get { return dpad_d; } set { dpad_d = value; } } + public GamePadConfigurationItem DPadLeft { get { return dpad_l; } set { dpad_l = value; } } + public GamePadConfigurationItem DPadRight { get { return dpad_r; } set { dpad_r = value; } } - public GamePadMap() + public GamePadConfiguration() { } - public GamePadMap(string configuration) + public GamePadConfiguration(string configuration) { } - static GamePadMap() + static GamePadConfiguration() { - GamePadMap map = new GamePadMap(); - map.A = new MapItem(JoystickButton.Button0); - map.B = new MapItem(JoystickButton.Button1); - map.X = new MapItem(JoystickButton.Button2); - map.Y = new MapItem(JoystickButton.Button3); - map.LeftShoulder = new MapItem(JoystickButton.Button4); - map.RightShoulder = new MapItem(JoystickButton.Button5); - map.LeftStick = new MapItem(JoystickButton.Button6); - map.RightStick = new MapItem(JoystickButton.Button7); - map.Start = new MapItem(JoystickButton.Button8); - map.Back = new MapItem(JoystickButton.Button9); - map.BigButton = new MapItem(JoystickButton.Button10); - map.DPadUp = new MapItem(JoystickButton.Button11); - map.DPadDown = new MapItem(JoystickButton.Button12); - map.DPadLeft = new MapItem(JoystickButton.Button13); - map.DPadRight = new MapItem(JoystickButton.Button14); - map.LeftAxisX = new MapItem(JoystickAxis.Axis0); - map.LeftAxisY = new MapItem(JoystickAxis.Axis1); - map.RightAxisX = new MapItem(JoystickAxis.Axis2); - map.RightAxisY = new MapItem(JoystickAxis.Axis3); - map.LeftTrigger = new MapItem(JoystickAxis.Axis4); - map.RightTrigger = new MapItem(JoystickAxis.Axis5); + GamePadConfiguration map = new GamePadConfiguration(); + map.A = new GamePadConfigurationItem(JoystickButton.Button0); + map.B = new GamePadConfigurationItem(JoystickButton.Button1); + map.X = new GamePadConfigurationItem(JoystickButton.Button2); + map.Y = new GamePadConfigurationItem(JoystickButton.Button3); + map.LeftShoulder = new GamePadConfigurationItem(JoystickButton.Button4); + map.RightShoulder = new GamePadConfigurationItem(JoystickButton.Button5); + map.LeftStick = new GamePadConfigurationItem(JoystickButton.Button6); + map.RightStick = new GamePadConfigurationItem(JoystickButton.Button7); + map.Start = new GamePadConfigurationItem(JoystickButton.Button8); + map.Back = new GamePadConfigurationItem(JoystickButton.Button9); + map.BigButton = new GamePadConfigurationItem(JoystickButton.Button10); + map.DPadUp = new GamePadConfigurationItem(JoystickButton.Button11); + map.DPadDown = new GamePadConfigurationItem(JoystickButton.Button12); + map.DPadLeft = new GamePadConfigurationItem(JoystickButton.Button13); + map.DPadRight = new GamePadConfigurationItem(JoystickButton.Button14); + map.LeftAxisX = new GamePadConfigurationItem(JoystickAxis.Axis0); + map.LeftAxisY = new GamePadConfigurationItem(JoystickAxis.Axis1); + map.RightAxisX = new GamePadConfigurationItem(JoystickAxis.Axis2); + map.RightAxisY = new GamePadConfigurationItem(JoystickAxis.Axis3); + map.LeftTrigger = new GamePadConfigurationItem(JoystickAxis.Axis4); + map.RightTrigger = new GamePadConfigurationItem(JoystickAxis.Axis5); default_map = map; } - public static GamePadMap Default + public static GamePadConfiguration Default { get { return default_map; } } - public static GamePadMap GetConfiguration(Guid guid) + public static GamePadConfiguration GetConfiguration(Guid guid) { - GamePadMap map = GamePadMap.Default; + GamePadConfiguration map = GamePadConfiguration.Default; if (GamePadConfigurationDatabase.Configurations.ContainsKey(guid)) { map = ParseConfiguration(GamePadConfigurationDatabase.Configurations[guid]); @@ -176,7 +128,7 @@ namespace OpenTK.Input // Parses a GamePad configuration string. The string // follows the rules for SDL2 GameController, outlined here: // http://wiki.libsdl.org/SDL_GameControllerAddMapping - static GamePadMap ParseConfiguration(string configuration) + static GamePadConfiguration ParseConfiguration(string configuration) { if (String.IsNullOrEmpty(configuration)) { @@ -194,13 +146,13 @@ namespace OpenTK.Input throw new ArgumentException(); } - GamePadMap map = new GamePadMap(); + GamePadConfiguration map = new GamePadConfiguration(); map.Guid = new Guid(items[0]); map.Name = items[1]; for (int i = 2; i < items.Length; i++) { string[] config = items[i].Split(':'); - MapItem map_item = ParseItem(config[1]); + GamePadConfigurationItem map_item = ParseItem(config[1]); switch (config[0]) { case "a": @@ -296,20 +248,20 @@ namespace OpenTK.Input return map; } - static MapItem ParseItem(string item) + static GamePadConfigurationItem ParseItem(string item) { if (String.IsNullOrEmpty(item)) { - return new MapItem(); + return new GamePadConfigurationItem(); } switch (item[0]) { case 'a': - return new MapItem(ParseAxis(item)); + return new GamePadConfigurationItem(ParseAxis(item)); case 'b': - return new MapItem(ParseButton(item)); + return new GamePadConfigurationItem(ParseButton(item)); case 'h': throw new NotImplementedException(); diff --git a/Source/OpenTK/Input/GamePadConfigurationItem.cs b/Source/OpenTK/Input/GamePadConfigurationItem.cs new file mode 100644 index 00000000..e9841074 --- /dev/null +++ b/Source/OpenTK/Input/GamePadConfigurationItem.cs @@ -0,0 +1,81 @@ +#region License +// +// GamePadConfigurationItem.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +#endregion + +using System; + +namespace OpenTK.Input +{ + enum ConfigurationType + { + Unmapped = 0, + Axis, + Button + } + + class GamePadConfigurationItem + { + ConfigurationType map_type; + Nullable map_button; + Nullable map_axis; + + public GamePadConfigurationItem() + { + } + + public GamePadConfigurationItem(JoystickAxis axis) + { + Type = ConfigurationType.Axis; + Axis = axis; + } + + public GamePadConfigurationItem(JoystickButton button) + { + Type = ConfigurationType.Button; + Button = button; + } + + public ConfigurationType Type + { + get { return map_type; } + private set { map_type = value; } + } + + public Nullable Axis + { + get { return map_axis; } + private set { map_axis = value; } + } + + public Nullable Button + { + get { return map_button; } + private set { map_button = value; } + } + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index ec3d8aff..13557288 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -791,8 +791,9 @@ - + + diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs index 8240d74c..6240ec4a 100644 --- a/Source/OpenTK/Platform/MappedGamePadDriver.cs +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -52,8 +52,8 @@ namespace OpenTK.Platform /// class MappedGamePadDriver : IGamePadDriver { - readonly Dictionary configurations = - new Dictionary(); + readonly Dictionary configurations = + new Dictionary(); public GamePadState GetState(int index) { @@ -61,7 +61,7 @@ namespace OpenTK.Platform GamePadState pad = new GamePadState(); if (joy.IsConnected) { - GamePadMap map = GetConfiguration(Joystick.GetGuid(index)); + GamePadConfiguration map = GetConfiguration(Joystick.GetGuid(index)); // Todo: implement mapping @@ -75,7 +75,7 @@ namespace OpenTK.Platform GamePadCapabilities pad; if (joy.IsConnected) { - GamePadMap map = GetConfiguration(Joystick.GetGuid(index)); + GamePadConfiguration map = GetConfiguration(Joystick.GetGuid(index)); pad = new GamePadCapabilities( GamePadType.GamePad, // Todo: detect different types TranslateAxes(map), @@ -95,7 +95,7 @@ namespace OpenTK.Platform string name = String.Empty; if (joy.IsConnected) { - GamePadMap map = GetConfiguration(Joystick.GetGuid(index)); + GamePadConfiguration map = GetConfiguration(Joystick.GetGuid(index)); name = map.Name; } return name; @@ -103,22 +103,22 @@ namespace OpenTK.Platform #region Private Members - GamePadMap GetConfiguration(Guid guid) + GamePadConfiguration GetConfiguration(Guid guid) { if (!configurations.ContainsKey(guid)) { - GamePadMap map = GamePadMap.GetConfiguration(guid); + GamePadConfiguration map = GamePadConfiguration.GetConfiguration(guid); configurations.Add(guid, map); } return configurations[guid]; } - bool IsMapped(MapItem item) + bool IsMapped(GamePadConfigurationItem item) { - return item.Type != MapType.Unmapped; + return item.Type != ConfigurationType.Unmapped; } - GamePadAxes TranslateAxes(GamePadMap map) + GamePadAxes TranslateAxes(GamePadConfiguration map) { GamePadAxes axes = 0; axes |= IsMapped(map.LeftAxisX) ? GamePadAxes.LeftX : 0; @@ -130,7 +130,7 @@ namespace OpenTK.Platform return axes; } - Buttons TranslateButtons(GamePadMap map) + Buttons TranslateButtons(GamePadConfiguration map) { Buttons buttons = 0; buttons |= IsMapped(map.A) ? Buttons.A : 0; From a8fb977017657046eda6944061fd3a0b7a636732 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 02:20:25 +0100 Subject: [PATCH 141/154] [Input] Initialize JoystickDevice.Details in constructor --- Source/OpenTK/Input/JoystickDevice.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Input/JoystickDevice.cs b/Source/OpenTK/Input/JoystickDevice.cs index d02d5b4c..55a92bef 100644 --- a/Source/OpenTK/Input/JoystickDevice.cs +++ b/Source/OpenTK/Input/JoystickDevice.cs @@ -156,12 +156,13 @@ namespace OpenTK.Input // Provides platform-specific information about the relevant JoystickDevice. internal sealed class JoystickDevice : JoystickDevice + where TDetail : new() { internal JoystickDevice(int id, int axes, int buttons) : base(id, axes, buttons) { } - internal TDetail Details; + internal TDetail Details = new TDetail(); } #endregion From 9e4827bf67b877b6487c834805de4ac570c138fe Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 02:20:51 +0100 Subject: [PATCH 142/154] [SDL2] Fixed SDL_JoystickGetGUID capitalization --- Source/OpenTK/Platform/SDL2/Sdl2.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 8ad25480..38ebef43 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -301,7 +301,7 @@ namespace OpenTK.Platform.SDL2 public static extern byte JoystickGetButton(IntPtr joystick, int button); [SuppressUnmanagedCodeSecurity] - [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickGetGuid", ExactSpelling = true)] + [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_JoystickGetGUID", ExactSpelling = true)] public static extern JoystickGuid JoystickGetGUID(IntPtr joystick); [SuppressUnmanagedCodeSecurity] From bf5d2a738d302004b0da9770647ee49b14eeeeb7 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 02:42:51 +0100 Subject: [PATCH 143/154] [Input] Made configuration database non-static --- .../Input/GamePadConfigurationDatabase.cs | 42 ++++++++++++++----- Source/OpenTK/Platform/MappedGamePadDriver.cs | 5 ++- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/Source/OpenTK/Input/GamePadConfigurationDatabase.cs b/Source/OpenTK/Input/GamePadConfigurationDatabase.cs index 95205993..06d3b12e 100644 --- a/Source/OpenTK/Input/GamePadConfigurationDatabase.cs +++ b/Source/OpenTK/Input/GamePadConfigurationDatabase.cs @@ -32,11 +32,11 @@ using System.Collections.Generic; namespace OpenTK.Input { - static class GamePadConfigurationDatabase + class GamePadConfigurationDatabase { - internal static readonly Dictionary Configurations = new Dictionary(); + readonly Dictionary Configurations = new Dictionary(); - static GamePadConfigurationDatabase() + internal GamePadConfigurationDatabase() { // Configuration database copied from SDL @@ -61,8 +61,10 @@ namespace OpenTK.Input // 3. This notice may not be removed or altered from any source distribution. #endregion - // Default configuration, used when no suitable configuration is available - Add("00000000000000000000000000000000,Unknown Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); + // Default configuration, used when no suitable configuration is available. + // Add("00000000000000000000000000000000,Unknown Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); + // Valid for all xinput devices on Windows: + Add("00000000000000000000000000000000,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,"); // Windows Add("341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,"); @@ -72,7 +74,6 @@ namespace OpenTK.Input Add("88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,"); Add("4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,"); Add("25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,"); - Add("xinput00000000000000000000000000,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,"); // Mac OS X Add("0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,"); @@ -99,11 +100,32 @@ namespace OpenTK.Input Add("030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,"); } - static void Add(string config) + internal void Add(string config) { - Configurations.Add( - new Guid(config.Substring(0, 32)), - config); + Guid guid = new Guid(config.Substring(0, 32)); + if (!Configurations.ContainsKey(guid)) + { + Configurations.Add(guid, config); + } + else + { + Configurations[guid] = config; + } + } + + internal string this[Guid guid] + { + get + { + if (Configurations.ContainsKey(guid)) + { + return Configurations[guid]; + } + else + { + return Configurations[new Guid()]; // default configuration + } + } } } } diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs index 6240ec4a..97cb1fae 100644 --- a/Source/OpenTK/Platform/MappedGamePadDriver.cs +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -52,6 +52,8 @@ namespace OpenTK.Platform /// class MappedGamePadDriver : IGamePadDriver { + readonly GamePadConfigurationDatabase database = + new GamePadConfigurationDatabase(); readonly Dictionary configurations = new Dictionary(); @@ -107,7 +109,8 @@ namespace OpenTK.Platform { if (!configurations.ContainsKey(guid)) { - GamePadConfiguration map = GamePadConfiguration.GetConfiguration(guid); + string config = database[guid]; + GamePadConfiguration map = new GamePadConfiguration(config); configurations.Add(guid, map); } return configurations[guid]; From 0593ea62e69aa18a2d08df093c8c002f382384a3 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 18:36:09 +0100 Subject: [PATCH 144/154] [Input] Added Source and Target to GamePadConfigurationItem --- Source/OpenTK/Input/ConfigurationType.cs | 41 +++++++++++ .../OpenTK/Input/GamePadConfigurationItem.cs | 47 ++++-------- .../Input/GamePadConfigurationSource.cs | 72 +++++++++++++++++++ .../Input/GamePadConfigurationTarget.cs | 72 +++++++++++++++++++ Source/OpenTK/OpenTK.csproj | 3 + 5 files changed, 200 insertions(+), 35 deletions(-) create mode 100644 Source/OpenTK/Input/ConfigurationType.cs create mode 100644 Source/OpenTK/Input/GamePadConfigurationSource.cs create mode 100644 Source/OpenTK/Input/GamePadConfigurationTarget.cs diff --git a/Source/OpenTK/Input/ConfigurationType.cs b/Source/OpenTK/Input/ConfigurationType.cs new file mode 100644 index 00000000..0cbb649a --- /dev/null +++ b/Source/OpenTK/Input/ConfigurationType.cs @@ -0,0 +1,41 @@ +#region License +// +// ConfigurationType.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +#endregion + +using System; + +namespace OpenTK.Input +{ + enum ConfigurationType + { + Unmapped = 0, + Axis, + Button + } +} + diff --git a/Source/OpenTK/Input/GamePadConfigurationItem.cs b/Source/OpenTK/Input/GamePadConfigurationItem.cs index e9841074..c2dba9f5 100644 --- a/Source/OpenTK/Input/GamePadConfigurationItem.cs +++ b/Source/OpenTK/Input/GamePadConfigurationItem.cs @@ -31,51 +31,28 @@ using System; namespace OpenTK.Input { - enum ConfigurationType - { - Unmapped = 0, - Axis, - Button - } - class GamePadConfigurationItem { - ConfigurationType map_type; - Nullable map_button; - Nullable map_axis; + GamePadConfigurationSource source; + GamePadConfigurationTarget target; - public GamePadConfigurationItem() + public GamePadConfigurationItem(GamePadConfigurationSource source, GamePadConfigurationTarget target) { + Source = source; + Target = target; } - public GamePadConfigurationItem(JoystickAxis axis) + public GamePadConfigurationSource Source { - Type = ConfigurationType.Axis; - Axis = axis; + get { return source; } + private set { source = value; } } - public GamePadConfigurationItem(JoystickButton button) + public GamePadConfigurationTarget Target { - Type = ConfigurationType.Button; - Button = button; - } - - public ConfigurationType Type - { - get { return map_type; } - private set { map_type = value; } - } - - public Nullable Axis - { - get { return map_axis; } - private set { map_axis = value; } - } - - public Nullable Button - { - get { return map_button; } - private set { map_button = value; } + get { return target; } + private set { target = value; } } } } + diff --git a/Source/OpenTK/Input/GamePadConfigurationSource.cs b/Source/OpenTK/Input/GamePadConfigurationSource.cs new file mode 100644 index 00000000..c1b25b82 --- /dev/null +++ b/Source/OpenTK/Input/GamePadConfigurationSource.cs @@ -0,0 +1,72 @@ +#region License +// +// GamePadConfigurationItem.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +#endregion + +using System; + +namespace OpenTK.Input +{ + struct GamePadConfigurationSource + { + ConfigurationType map_type; + Nullable map_button; + Nullable map_axis; + + public GamePadConfigurationSource(JoystickAxis axis) + : this() + { + Type = ConfigurationType.Axis; + Axis = axis; + } + + public GamePadConfigurationSource(JoystickButton button) + : this() + { + Type = ConfigurationType.Button; + Button = button; + } + + public ConfigurationType Type + { + get { return map_type; } + private set { map_type = value; } + } + + public JoystickAxis Axis + { + get { return map_axis.Value; } + private set { map_axis = value; } + } + + public JoystickButton Button + { + get { return map_button.Value; } + private set { map_button = value; } + } + } +} diff --git a/Source/OpenTK/Input/GamePadConfigurationTarget.cs b/Source/OpenTK/Input/GamePadConfigurationTarget.cs new file mode 100644 index 00000000..75199c9f --- /dev/null +++ b/Source/OpenTK/Input/GamePadConfigurationTarget.cs @@ -0,0 +1,72 @@ +#region License +// +// GamePadConfigurationTarget.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +#endregion + +using System; + +namespace OpenTK.Input +{ + struct GamePadConfigurationTarget + { + ConfigurationType map_type; + Nullable map_button; + Nullable map_axis; + + public GamePadConfigurationTarget(Buttons button) + : this() + { + Type = ConfigurationType.Button; + map_button = button; + } + + public GamePadConfigurationTarget(GamePadAxes axis) + : this() + { + Type = ConfigurationType.Axis; + map_axis = axis; + } + + public ConfigurationType Type + { + get { return map_type; } + private set { map_type = value; } + } + + public GamePadAxes Axis + { + get { return map_axis.Value; } + private set { map_axis = value; } + } + + public Buttons Button + { + get { return map_button.Value; } + private set { map_button = value; } + } + } +} diff --git a/Source/OpenTK/OpenTK.csproj b/Source/OpenTK/OpenTK.csproj index 13557288..93d0a425 100644 --- a/Source/OpenTK/OpenTK.csproj +++ b/Source/OpenTK/OpenTK.csproj @@ -793,6 +793,9 @@ + + + From 8f00bbc9f20f4a1285bdbaf95d652a2c270e242c Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 18:36:27 +0100 Subject: [PATCH 145/154] [Input] Added internal Joystick.GetAxisRaw() method --- Source/OpenTK/Input/JoystickState.cs | 30 ++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index e14ac2d2..7f1624d8 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -56,16 +56,7 @@ namespace OpenTK.Input public float GetAxis(int axis) { - float value = 0.0f; - if (axis >= 0 && axis < MaxAxes) - { - value = GetAxisUnsafe(axis) * ConversionFactor; - } - else - { - Debug.Print("[Joystick] Invalid axis {0}", axis); - } - return value; + return GetAxisRaw(axis) * ConversionFactor; } public ButtonState GetButton(JoystickButton button) @@ -124,6 +115,25 @@ namespace OpenTK.Input #region Internal Members + internal short GetAxisRaw(JoystickAxis axis) + { + return GetAxisRaw((int)axis); + } + + internal short GetAxisRaw(int axis) + { + short value = 0; + if (axis >= 0 && axis < MaxAxes) + { + value = GetAxisUnsafe(axis); + } + else + { + Debug.Print("[Joystick] Invalid axis {0}", axis); + } + return value; + } + internal void SetAxis(JoystickAxis axis, short value) { int index = (int)axis; From d49af2787f89e9d5ba4d76e5b818073db2a0ea74 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 18:37:20 +0100 Subject: [PATCH 146/154] [Input] Simplified configuration parser and added GetEnumerator() --- Source/OpenTK/Input/GamePadConfiguration.cs | 263 +++++++------------- 1 file changed, 88 insertions(+), 175 deletions(-) diff --git a/Source/OpenTK/Input/GamePadConfiguration.cs b/Source/OpenTK/Input/GamePadConfiguration.cs index 887ba6a1..54600e79 100644 --- a/Source/OpenTK/Input/GamePadConfiguration.cs +++ b/Source/OpenTK/Input/GamePadConfiguration.cs @@ -34,101 +34,43 @@ using System.Text; namespace OpenTK.Input { - class GamePadConfiguration + sealed class GamePadConfiguration { - static readonly GamePadConfiguration default_map; + static readonly char[] ConfigurationSeparator = new char[] { ',' }; Guid guid; string name; - GamePadConfigurationItem a, b, x, y; - GamePadConfigurationItem lshoulder, rshoulder; - GamePadConfigurationItem lstick, rstick; - GamePadConfigurationItem start, back; - GamePadConfigurationItem home; - GamePadConfigurationItem axis_lx, axis_ly; - GamePadConfigurationItem axis_rx, axis_ry; - GamePadConfigurationItem ltrigger, rtrigger; - GamePadConfigurationItem dpad_u, dpad_d; - GamePadConfigurationItem dpad_l, dpad_r; + readonly List configuration_items = + new List(); - Guid Guid { get { return guid; } set { guid = value; } } - public string Name { get { return name; } set { name = value; } } - public GamePadConfigurationItem A { get { return a; } set { a = value; } } - public GamePadConfigurationItem B { get { return b; } set { b = value; } } - public GamePadConfigurationItem X { get { return x; } set { x = value; } } - public GamePadConfigurationItem Y { get { return y; } set { y = value; } } - public GamePadConfigurationItem LeftShoulder { get { return lshoulder; } set { lshoulder = value; } } - public GamePadConfigurationItem RightShoulder { get { return rshoulder; } set { rshoulder = value; } } - public GamePadConfigurationItem LeftStick { get { return lstick; } set { lstick = value; } } - public GamePadConfigurationItem RightStick { get { return rstick; } set { rstick = value; } } - public GamePadConfigurationItem Start { get { return start; } set { start = value; } } - public GamePadConfigurationItem Back { get { return back; } set { back = value; } } - public GamePadConfigurationItem BigButton { get { return home; } set { home = value; } } - public GamePadConfigurationItem LeftAxisX { get { return axis_lx; } set { axis_lx = value; } } - public GamePadConfigurationItem LeftAxisY { get { return axis_ly; } set { axis_ly = value; } } - public GamePadConfigurationItem RightAxisX { get { return axis_rx; } set { axis_rx = value; } } - public GamePadConfigurationItem RightAxisY { get { return axis_ry; } set { axis_ry = value; } } - public GamePadConfigurationItem LeftTrigger { get { return ltrigger; } set { ltrigger = value; } } - public GamePadConfigurationItem RightTrigger { get { return rtrigger; } set { rtrigger = value; } } - public GamePadConfigurationItem DPadUp { get { return dpad_u; } set { dpad_u = value; } } - public GamePadConfigurationItem DPadDown { get { return dpad_d; } set { dpad_d = value; } } - public GamePadConfigurationItem DPadLeft { get { return dpad_l; } set { dpad_l = value; } } - public GamePadConfigurationItem DPadRight { get { return dpad_r; } set { dpad_r = value; } } - - public GamePadConfiguration() + public Guid Guid { + get { return guid; } + private set { guid = value; } + } + + public string Name + { + get { return name; } + private set { name = value; } } public GamePadConfiguration(string configuration) { + ParseConfiguration(configuration); } - static GamePadConfiguration() + public List.Enumerator GetEnumerator() { - GamePadConfiguration map = new GamePadConfiguration(); - map.A = new GamePadConfigurationItem(JoystickButton.Button0); - map.B = new GamePadConfigurationItem(JoystickButton.Button1); - map.X = new GamePadConfigurationItem(JoystickButton.Button2); - map.Y = new GamePadConfigurationItem(JoystickButton.Button3); - map.LeftShoulder = new GamePadConfigurationItem(JoystickButton.Button4); - map.RightShoulder = new GamePadConfigurationItem(JoystickButton.Button5); - map.LeftStick = new GamePadConfigurationItem(JoystickButton.Button6); - map.RightStick = new GamePadConfigurationItem(JoystickButton.Button7); - map.Start = new GamePadConfigurationItem(JoystickButton.Button8); - map.Back = new GamePadConfigurationItem(JoystickButton.Button9); - map.BigButton = new GamePadConfigurationItem(JoystickButton.Button10); - map.DPadUp = new GamePadConfigurationItem(JoystickButton.Button11); - map.DPadDown = new GamePadConfigurationItem(JoystickButton.Button12); - map.DPadLeft = new GamePadConfigurationItem(JoystickButton.Button13); - map.DPadRight = new GamePadConfigurationItem(JoystickButton.Button14); - map.LeftAxisX = new GamePadConfigurationItem(JoystickAxis.Axis0); - map.LeftAxisY = new GamePadConfigurationItem(JoystickAxis.Axis1); - map.RightAxisX = new GamePadConfigurationItem(JoystickAxis.Axis2); - map.RightAxisY = new GamePadConfigurationItem(JoystickAxis.Axis3); - map.LeftTrigger = new GamePadConfigurationItem(JoystickAxis.Axis4); - map.RightTrigger = new GamePadConfigurationItem(JoystickAxis.Axis5); - default_map = map; + return configuration_items.GetEnumerator(); } - public static GamePadConfiguration Default - { - get { return default_map; } - } - - public static GamePadConfiguration GetConfiguration(Guid guid) - { - GamePadConfiguration map = GamePadConfiguration.Default; - if (GamePadConfigurationDatabase.Configurations.ContainsKey(guid)) - { - map = ParseConfiguration(GamePadConfigurationDatabase.Configurations[guid]); - } - return map; - } + #region Private Members // Parses a GamePad configuration string. The string // follows the rules for SDL2 GameController, outlined here: // http://wiki.libsdl.org/SDL_GameControllerAddMapping - static GamePadConfiguration ParseConfiguration(string configuration) + void ParseConfiguration(string configuration) { if (String.IsNullOrEmpty(configuration)) { @@ -140,128 +82,97 @@ namespace OpenTK.Input // - name is a human-readable name for the controller // - config is a comma-separated list of configurations as follows: // - [gamepad axis or button name]:[joystick axis, button or hat number] - string[] items = configuration.Split(','); + string[] items = configuration.Split(ConfigurationSeparator, StringSplitOptions.RemoveEmptyEntries); if (items.Length < 3) { throw new ArgumentException(); } - GamePadConfiguration map = new GamePadConfiguration(); + GamePadConfiguration map = this; map.Guid = new Guid(items[0]); map.Name = items[1]; for (int i = 2; i < items.Length; i++) { string[] config = items[i].Split(':'); - GamePadConfigurationItem map_item = ParseItem(config[1]); - switch (config[0]) - { - case "a": - map.A = map_item; - break; - - case "b": - map.B = map_item; - break; - - case "x": - map.X = map_item; - break; - - case "y": - map.Y = map_item; - break; - - case "start": - map.Start = map_item; - break; - - case "back": - map.Back = map_item; - break; - - case "guide": - map.BigButton = map_item; - break; - - case "dpup": - map.DPadUp = map_item; - break; - - case "dpdown": - map.DPadDown = map_item; - break; - - case "dpleft": - map.DPadLeft = map_item; - break; - - case "dpright": - map.DPadRight = map_item; - break; - - case "leftshoulder": - map.LeftShoulder = map_item; - break; - - case "rightshoulder": - map.RightShoulder = map_item; - break; - - case "leftstick": - map.LeftStick = map_item; - break; - - case "rightstick": - map.RightStick = map_item; - break; - - case "leftx": - map.LeftAxisX = map_item; - break; - - case "lefty": - map.LeftAxisY = map_item; - break; - - case "rightx": - map.RightAxisX = map_item; - break; - - case "righty": - map.RightAxisY = map_item; - break; - - case "lefttrigger": - map.LeftTrigger = map_item; - break; - - case "righttrigger": - map.RightTrigger = map_item; - break; - - default: - Debug.Print("[Input] Invalid GamePad configuration name: {0}", items[i]); - break; - } + GamePadConfigurationTarget target = ParseTarget(config[0]); + GamePadConfigurationSource source = ParseSource(config[1]); + configuration_items.Add(new GamePadConfigurationItem(source, target)); } - - return map; } - static GamePadConfigurationItem ParseItem(string item) + static GamePadConfigurationTarget ParseTarget(string target) + { + switch (target) + { + // Buttons + case "a": + return new GamePadConfigurationTarget(Buttons.A); + case "b": + return new GamePadConfigurationTarget(Buttons.B); + case "x": + return new GamePadConfigurationTarget(Buttons.X); + case "y": + return new GamePadConfigurationTarget(Buttons.Y); + case "start": + return new GamePadConfigurationTarget(Buttons.Start); + case "back": + return new GamePadConfigurationTarget(Buttons.Back); + case "guide": + return new GamePadConfigurationTarget(Buttons.BigButton); + case "leftshoulder": + return new GamePadConfigurationTarget(Buttons.LeftShoulder); + case "rightshoulder": + return new GamePadConfigurationTarget(Buttons.RightShoulder); + case "leftstick": + return new GamePadConfigurationTarget(Buttons.LeftStick); + case "rightstick": + return new GamePadConfigurationTarget(Buttons.RightStick); + case "dpup": + return new GamePadConfigurationTarget(Buttons.DPadUp); + case "dpdown": + return new GamePadConfigurationTarget(Buttons.DPadDown); + case "dpleft": + return new GamePadConfigurationTarget(Buttons.DPadLeft); + case "dpright": + return new GamePadConfigurationTarget(Buttons.DPadRight); + + // Axes + case "leftx": + return new GamePadConfigurationTarget(GamePadAxes.LeftX); + case "lefty": + return new GamePadConfigurationTarget(GamePadAxes.LeftY); + case "rightx": + return new GamePadConfigurationTarget(GamePadAxes.RightX); + case "righty": + return new GamePadConfigurationTarget(GamePadAxes.RightY); + + // Triggers + case "lefttrigger": + return new GamePadConfigurationTarget(GamePadAxes.LeftTrigger); + case "righttrigger": + return new GamePadConfigurationTarget(GamePadAxes.RightTrigger); + + + // Unmapped + default: + return new GamePadConfigurationTarget(); + } + } + + static GamePadConfigurationSource ParseSource(string item) { if (String.IsNullOrEmpty(item)) { - return new GamePadConfigurationItem(); + return new GamePadConfigurationSource(); } switch (item[0]) { case 'a': - return new GamePadConfigurationItem(ParseAxis(item)); + return new GamePadConfigurationSource(ParseAxis(item)); case 'b': - return new GamePadConfigurationItem(ParseButton(item)); + return new GamePadConfigurationSource(ParseButton(item)); case 'h': throw new NotImplementedException(); @@ -287,5 +198,7 @@ namespace OpenTK.Input int id = Int32.Parse(item.Substring(1)); return button + id; } + + #endregion } } From b5d42b79925cfd2d05d56ba2caebfd437ecfb147 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 18:37:53 +0100 Subject: [PATCH 147/154] [Input] Implemented GetState() and simplified GetCapabilities() --- Source/OpenTK/Platform/MappedGamePadDriver.cs | 112 +++++++++++------- 1 file changed, 69 insertions(+), 43 deletions(-) diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs index 97cb1fae..afe839c4 100644 --- a/Source/OpenTK/Platform/MappedGamePadDriver.cs +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -61,13 +61,59 @@ namespace OpenTK.Platform { JoystickState joy = Joystick.GetState(index); GamePadState pad = new GamePadState(); + if (joy.IsConnected) { - GamePadConfiguration map = GetConfiguration(Joystick.GetGuid(index)); + pad.SetConnected(true); + GamePadConfiguration configuration = GetConfiguration(Joystick.GetGuid(index)); + foreach (GamePadConfigurationItem map in configuration) + { + switch (map.Source.Type) + { + case ConfigurationType.Axis: + { + // JoystickAxis -> Buttons/GamePadAxes mapping + JoystickAxis source_axis = map.Source.Axis; + GamePadAxes target_axis = map.Target.Axis; + short value = joy.GetAxisRaw(source_axis); - // Todo: implement mapping + switch (map.Target.Type) + { + case ConfigurationType.Axis: + pad.SetAxis(target_axis, value); + break; + + case ConfigurationType.Button: + throw new NotImplementedException(); + break; + } + } + break; + + case ConfigurationType.Button: + { + // JoystickButton -> Buttons/GamePadAxes mapping + JoystickButton source_button = map.Source.Button; + Buttons target_button = map.Target.Button; + bool pressed = joy.GetButton(source_button) == ButtonState.Pressed; + + switch (map.Target.Type) + { + case ConfigurationType.Axis: + throw new NotImplementedException(); + break; + + case ConfigurationType.Button: + pad.SetButton(target_button, pressed); + break; + } + } + break; + } + } } + return pad; } @@ -77,11 +123,28 @@ namespace OpenTK.Platform GamePadCapabilities pad; if (joy.IsConnected) { - GamePadConfiguration map = GetConfiguration(Joystick.GetGuid(index)); + GamePadConfiguration configuration = GetConfiguration(Joystick.GetGuid(index)); + GamePadAxes mapped_axes = 0; + Buttons mapped_buttons = 0; + + foreach (GamePadConfigurationItem map in configuration) + { + switch (map.Target.Type) + { + case ConfigurationType.Axis: + mapped_axes |= map.Target.Axis; + break; + + case ConfigurationType.Button: + mapped_buttons |= map.Target.Button; + break; + } + } + pad = new GamePadCapabilities( GamePadType.GamePad, // Todo: detect different types - TranslateAxes(map), - TranslateButtons(map), + mapped_axes, + mapped_buttons, true); } else @@ -116,48 +179,11 @@ namespace OpenTK.Platform return configurations[guid]; } - bool IsMapped(GamePadConfigurationItem item) + bool IsMapped(GamePadConfigurationSource item) { return item.Type != ConfigurationType.Unmapped; } - GamePadAxes TranslateAxes(GamePadConfiguration map) - { - GamePadAxes axes = 0; - axes |= IsMapped(map.LeftAxisX) ? GamePadAxes.LeftX : 0; - axes |= IsMapped(map.LeftAxisY) ? GamePadAxes.LeftY : 0; - axes |= IsMapped(map.RightAxisX) ? GamePadAxes.RightX : 0; - axes |= IsMapped(map.RightAxisY) ? GamePadAxes.RightY : 0; - axes |= IsMapped(map.LeftTrigger) ? GamePadAxes.LeftTrigger : 0; - axes |= IsMapped(map.RightTrigger) ? GamePadAxes.RightTrigger : 0; - return axes; - } - - Buttons TranslateButtons(GamePadConfiguration map) - { - Buttons buttons = 0; - buttons |= IsMapped(map.A) ? Buttons.A : 0; - buttons |= IsMapped(map.B) ? Buttons.B : 0; - buttons |= IsMapped(map.X) ? Buttons.X : 0; - buttons |= IsMapped(map.Y) ? Buttons.Y : 0; - buttons |= IsMapped(map.Start) ? Buttons.Start : 0; - buttons |= IsMapped(map.Back) ? Buttons.Back : 0; - buttons |= IsMapped(map.BigButton) ? Buttons.BigButton : 0; - buttons |= IsMapped(map.LeftShoulder) ? Buttons.LeftShoulder : 0; - buttons |= IsMapped(map.RightShoulder) ? Buttons.RightShoulder : 0; - buttons |= IsMapped(map.LeftStick) ? Buttons.LeftStick : 0; - buttons |= IsMapped(map.RightStick) ? Buttons.RightStick : 0; - return buttons; - } - -// bool TranslateDPad(GamePadMap map) -// { -// pad.HasDPadDownButton = IsMapped(map.DPadDown); -// pad.HasDPadUpButton = IsMapped(map.DPadUp); -// pad.HasDPadLeftButton = IsMapped(map.DPadLeft); -// pad.HasDPadRightButton = IsMapped(map.DPadRight); -// } - #endregion } } From 1ccf7e5ad22d7d0f7e67575e0f65945e49758b48 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 19:24:15 +0100 Subject: [PATCH 148/154] [Input] Added PacketNumber property --- Source/OpenTK/Input/GamePadState.cs | 11 +++++++++++ Source/OpenTK/Input/JoystickState.cs | 11 +++++++++++ Source/OpenTK/Platform/MappedGamePadDriver.cs | 2 ++ 3 files changed, 24 insertions(+) diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index 179762b3..60318dae 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -37,6 +37,7 @@ namespace OpenTK.Input const float RangeMultiplier = 1.0f / (short.MaxValue + 1); Buttons buttons; + int packet_number; short left_stick_x; short left_stick_y; short right_stick_x; @@ -72,6 +73,11 @@ namespace OpenTK.Input get { return is_connected; } } + public int PacketNumber + { + get { return packet_number; } + } + public override string ToString() { return String.Format( @@ -167,6 +173,11 @@ namespace OpenTK.Input right_trigger = right; } + internal void SetPacketNumber(int number) + { + packet_number = number; + } + #endregion #region Private Members diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index 7f1624d8..e8e2abf2 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -45,6 +45,7 @@ namespace OpenTK.Input unsafe fixed short axes[MaxAxes]; int buttons; + int packet_number; bool is_connected; #region Public Members @@ -79,6 +80,11 @@ namespace OpenTK.Input get { return is_connected; } } + internal int PacketNumber + { + get { return packet_number; } + } + public override string ToString() { StringBuilder sb = new StringBuilder(); @@ -167,6 +173,11 @@ namespace OpenTK.Input is_connected = value; } + internal void SetPacketNumber(int number) + { + packet_number = number; + } + #endregion #region Private Members diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs index afe839c4..20da30a8 100644 --- a/Source/OpenTK/Platform/MappedGamePadDriver.cs +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -65,6 +65,8 @@ namespace OpenTK.Platform if (joy.IsConnected) { pad.SetConnected(true); + pad.SetPacketNumber(joy.PacketNumber); + GamePadConfiguration configuration = GetConfiguration(Joystick.GetGuid(index)); foreach (GamePadConfigurationItem map in configuration) From b513e35ea8a3169754a993447fd7ed1bf4c96714 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 19:24:38 +0100 Subject: [PATCH 149/154] [SDL2] Implemented PacketNumber property --- Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index 25b6b253..faff9226 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -42,6 +42,7 @@ namespace OpenTK.Platform.SDL2 { public IntPtr Handle { get; set; } public Guid Guid { get; set; } + public int PacketNumber { get; set; } public int HatCount { get; set; } public int BallCount { get; set; } public bool IsConnected { get; set; } @@ -73,7 +74,6 @@ namespace OpenTK.Platform.SDL2 readonly Dictionary sdl_instanceid_to_controllers = new Dictionary(); #endif - public Sdl2JoystickDriver() { joysticks_readonly = joysticks.AsReadOnly(); @@ -339,6 +339,7 @@ namespace OpenTK.Platform.SDL2 JoystickDevice joystick = (JoystickDevice)joysticks[index]; float value = ev.Value * RangeMultiplier; joystick.SetAxis((JoystickAxis)ev.Axis, value); + joystick.Details.PacketNumber = Math.Max(0, unchecked(joystick.Details.PacketNumber + 1)); } else { @@ -354,6 +355,7 @@ namespace OpenTK.Platform.SDL2 int index = sdl_instanceid_to_joysticks[id]; JoystickDevice joystick = (JoystickDevice)joysticks[index]; // Todo: does it make sense to support balls? + joystick.Details.PacketNumber = Math.Max(0, unchecked(joystick.Details.PacketNumber + 1)); } else { @@ -369,6 +371,7 @@ namespace OpenTK.Platform.SDL2 int index = sdl_instanceid_to_joysticks[id]; JoystickDevice joystick = (JoystickDevice)joysticks[index]; joystick.SetButton((JoystickButton)ev.Button, ev.State == State.Pressed); + joystick.Details.PacketNumber = Math.Max(0, unchecked(joystick.Details.PacketNumber + 1)); } else { @@ -384,6 +387,7 @@ namespace OpenTK.Platform.SDL2 int index = sdl_instanceid_to_joysticks[id]; JoystickDevice joystick = (JoystickDevice)joysticks[index]; // Todo: map hat to an extra axis + joystick.Details.PacketNumber = Math.Max(0, unchecked(joystick.Details.PacketNumber + 1)); } else { @@ -588,6 +592,7 @@ namespace OpenTK.Platform.SDL2 } state.SetIsConnected(joystick.Details.IsConnected); + state.SetPacketNumber(joystick.Details.PacketNumber); } return state; From ec43b9ff850c2a9e684591c407824fa95ebbf025 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 19:27:04 +0100 Subject: [PATCH 150/154] [Input] GamePad and Joystick classes should be sealed --- Source/OpenTK/Input/GamePad.cs | 4 +++- Source/OpenTK/Input/Joystick.cs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/OpenTK/Input/GamePad.cs b/Source/OpenTK/Input/GamePad.cs index a0a63f49..8f8468d1 100644 --- a/Source/OpenTK/Input/GamePad.cs +++ b/Source/OpenTK/Input/GamePad.cs @@ -32,7 +32,7 @@ namespace OpenTK.Input /// /// Provides access to GamePad devices. /// - public class GamePad + public sealed class GamePad { internal const int MaxAxisCount = 10; internal const int MaxDPadCount = 2; @@ -40,6 +40,8 @@ namespace OpenTK.Input static readonly IGamePadDriver driver = Platform.Factory.Default.CreateGamePadDriver(); + private GamePad() { } + /// /// Retrieves a GamePadCapabilities structure describing the /// capabilities of a gamepad device. diff --git a/Source/OpenTK/Input/Joystick.cs b/Source/OpenTK/Input/Joystick.cs index 2b10cfb9..7f1037e1 100644 --- a/Source/OpenTK/Input/Joystick.cs +++ b/Source/OpenTK/Input/Joystick.cs @@ -33,11 +33,13 @@ using System.Text; namespace OpenTK.Input { - public class Joystick + public sealed class Joystick { static readonly IJoystickDriver2 implementation = Platform.Factory.Default.CreateJoystickDriver(); + private Joystick() { } + public static JoystickCapabilities GetCapabilities(int index) { return implementation.GetCapabilities(index); From 8649e4a044f16e52465dccf200b353b209a6f781 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Thu, 2 Jan 2014 19:52:00 +0100 Subject: [PATCH 151/154] [Input] Added SetVibration() API skeleton --- Source/OpenTK/Input/GamePad.cs | 17 +++++++++++++++++ Source/OpenTK/Input/IGamePadDriver.cs | 2 ++ Source/OpenTK/Platform/MappedGamePadDriver.cs | 5 +++++ .../OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs | 5 +++++ .../OpenTK/Platform/Windows/XInputJoystick.cs | 7 ++++++- Source/OpenTK/Platform/X11/X11Joystick.cs | 17 +++++++++++------ 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/Source/OpenTK/Input/GamePad.cs b/Source/OpenTK/Input/GamePad.cs index 8f8468d1..50df2667 100644 --- a/Source/OpenTK/Input/GamePad.cs +++ b/Source/OpenTK/Input/GamePad.cs @@ -65,5 +65,22 @@ namespace OpenTK.Input { return driver.GetState(index); } + + /// + /// Sets the vibration intensity for the left and right motors of this + /// + /// + /// true, if vibration was set, false otherwise. This method can return false + /// if the GamePad hardware does not support vibration or if it cannot respond to + /// the command for any reason. Do not loop until this becomes true, but rather ignore + /// a return value of false. + /// + /// A zero-based device index for the GamePad device to affect + /// The vibration intensity for the left motor, between 0.0 and 1.0. + /// The vibration intensity for the right motor, between 0.0 and 1.0. + public static bool SetVibration(int index, float left, float right) + { + return driver.SetVibration(index, left, right); + } } } diff --git a/Source/OpenTK/Input/IGamePadDriver.cs b/Source/OpenTK/Input/IGamePadDriver.cs index fc24c8f8..6852dedf 100644 --- a/Source/OpenTK/Input/IGamePadDriver.cs +++ b/Source/OpenTK/Input/IGamePadDriver.cs @@ -19,5 +19,7 @@ namespace OpenTK.Input /// /// If no device exists at the specified index, the return value is . string GetName(int index); + + bool SetVibration(int index, float left, float right); } } diff --git a/Source/OpenTK/Platform/MappedGamePadDriver.cs b/Source/OpenTK/Platform/MappedGamePadDriver.cs index 20da30a8..12f918c9 100644 --- a/Source/OpenTK/Platform/MappedGamePadDriver.cs +++ b/Source/OpenTK/Platform/MappedGamePadDriver.cs @@ -168,6 +168,11 @@ namespace OpenTK.Platform return name; } + public bool SetVibration(int index, float left, float right) + { + return false; + } + #region Private Members GamePadConfiguration GetConfiguration(Guid guid) diff --git a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs index faff9226..8a08151a 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2JoystickDriver.cs @@ -567,6 +567,11 @@ namespace OpenTK.Platform.SDL2 { return gamepad_driver.GetName(index); } + + public bool SetVibration(int index, float left, float right) + { + return false; + } #endif #endregion diff --git a/Source/OpenTK/Platform/Windows/XInputJoystick.cs b/Source/OpenTK/Platform/Windows/XInputJoystick.cs index 23710df0..910a7f01 100644 --- a/Source/OpenTK/Platform/Windows/XInputJoystick.cs +++ b/Source/OpenTK/Platform/Windows/XInputJoystick.cs @@ -87,7 +87,12 @@ namespace OpenTK.Platform.Windows public string GetName(int index) { - throw new NotImplementedException(); + return String.Empty; + } + + public bool SetVibration(int index, float left, float right) + { + return false; } #endregion diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs index 5f76dd54..cbab7099 100644 --- a/Source/OpenTK/Platform/X11/X11Joystick.cs +++ b/Source/OpenTK/Platform/X11/X11Joystick.cs @@ -263,17 +263,22 @@ namespace OpenTK.Platform.X11 public GamePadCapabilities GetCapabilities(int index) { - throw new NotImplementedException(); + return new GamePadCapabilities(); } public GamePadState GetState(int index) { - throw new NotImplementedException(); + return new GamePadState(); } public string GetName(int index) { - throw new NotImplementedException(); + return String.Empty; + } + + public bool SetVibration(int index, float left, float right) + { + return false; } #endregion @@ -282,17 +287,17 @@ namespace OpenTK.Platform.X11 JoystickState IJoystickDriver2.GetState(int index) { - throw new NotImplementedException(); + return new JoystickState(); } JoystickCapabilities IJoystickDriver2.GetCapabilities(int index) { - throw new NotImplementedException(); + return new JoystickCapabilities(); } Guid IJoystickDriver2.GetGuid(int index) { - throw new NotImplementedException(); + return new Guid(); } #endregion From b35aad15034b2541560928f334a54f6ef4027d52 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 3 Jan 2014 01:58:08 +0100 Subject: [PATCH 152/154] [Input] Removed JoystickState.GetAxis(int) overload --- Source/OpenTK/Input/JoystickState.cs | 69 +++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index e8e2abf2..f00a5521 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -34,6 +34,9 @@ using System.Text; namespace OpenTK.Input { + /// + /// Describes the current state of a . + /// public struct JoystickState : IEquatable { // If we ever add more values to JoystickAxis or JoystickButton @@ -50,48 +53,70 @@ namespace OpenTK.Input #region Public Members + /// + /// Gets a value between -1.0 and 1.0 representing the current offset of the specified . + /// + /// + /// A value between -1.0 and 1.0 representing offset of the specified + /// to query the number of available axes. + /// + /// The to query. public float GetAxis(JoystickAxis axis) - { - return GetAxis((int)axis); - } - - public float GetAxis(int axis) { return GetAxisRaw(axis) * ConversionFactor; } + /// + /// Gets the current of the specified . + /// + /// if the specified button is pressed; otherwise, . + /// The to query. public ButtonState GetButton(JoystickButton button) { return (buttons & (1 << (int)button)) != 0 ? ButtonState.Pressed : ButtonState.Released; } + /// + /// Gets a value indicating whether the specified is currently pressed. + /// + /// true if the specified button is pressed; otherwise, false. + /// The to query. public bool IsButtonDown(JoystickButton button) { return (buttons & (1 << (int)button)) != 0; } + /// + /// Gets a value indicating whether the specified is currently released. + /// + /// true if the specified button is released; otherwise, false. + /// The to query. public bool IsButtonUp(JoystickButton button) { return (buttons & (1 << (int)button)) == 0; } + /// + /// Gets a value indicating whether this instance is connected. + /// + /// true if this instance is connected; otherwise, false. public bool IsConnected { get { return is_connected; } } - internal int PacketNumber - { - get { return packet_number; } - } - + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < MaxAxes; i++) { sb.Append(" "); - sb.Append(String.Format("{0:f4}", GetAxis(i))); + sb.Append(String.Format("{0:f4}", GetAxis(JoystickAxis.Axis0 + i))); } return String.Format( "{{Axes:{0}; Buttons: {1}; IsConnected: {2}}}", @@ -100,6 +125,11 @@ namespace OpenTK.Input IsConnected); } + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. public override int GetHashCode() { int hash = buttons.GetHashCode() ^ IsConnected.GetHashCode(); @@ -110,6 +140,12 @@ namespace OpenTK.Input return hash; } + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals(object obj) { return @@ -121,6 +157,11 @@ namespace OpenTK.Input #region Internal Members + internal int PacketNumber + { + get { return packet_number; } + } + internal short GetAxisRaw(JoystickAxis axis) { return GetAxisRaw((int)axis); @@ -197,6 +238,12 @@ namespace OpenTK.Input #region IEquatable Members + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals(JoystickState other) { bool equals = From 3095afa18a10a758204a131621765923361cd7fe Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 3 Jan 2014 01:58:16 +0100 Subject: [PATCH 153/154] [Input] Documented all public members --- Source/OpenTK/Input/Buttons.cs | 2 +- Source/OpenTK/Input/GamePad.cs | 62 +++++++++------ Source/OpenTK/Input/GamePadButtons.cs | 76 +++++++++++++++++- Source/OpenTK/Input/GamePadDPad.cs | 87 ++++++++++++++++++++- Source/OpenTK/Input/GamePadState.cs | 49 +++++++++++- Source/OpenTK/Input/GamePadThumbSticks.cs | 39 ++++++++- Source/OpenTK/Input/GamePadTriggers.cs | 34 ++++++++ Source/OpenTK/Input/GamePadType.cs | 50 ++++++++++++ Source/OpenTK/Input/Joystick.cs | 29 +++++++ Source/OpenTK/Input/JoystickCapabilities.cs | 36 ++++++++- 10 files changed, 426 insertions(+), 38 deletions(-) diff --git a/Source/OpenTK/Input/Buttons.cs b/Source/OpenTK/Input/Buttons.cs index 878c738f..319e2183 100644 --- a/Source/OpenTK/Input/Buttons.cs +++ b/Source/OpenTK/Input/Buttons.cs @@ -28,7 +28,7 @@ using System; namespace OpenTK.Input { /// - /// Enumerates available buttons for a canonical GamePad device. + /// Enumerates available buttons for a GamePad device. /// [Flags] public enum Buttons diff --git a/Source/OpenTK/Input/GamePad.cs b/Source/OpenTK/Input/GamePad.cs index 50df2667..11213597 100644 --- a/Source/OpenTK/Input/GamePad.cs +++ b/Source/OpenTK/Input/GamePad.cs @@ -1,29 +1,31 @@ - #region License - // - // The Open Toolkit Library License - // - // Copyright (c) 2006 - 2009 the Open Toolkit library. - // - // 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 +#region License +// +// GamePadButtons.cs +// +// Author: +// Stefanos A. +// +// Copyright (c) 2006-2014 Stefanos Apostolopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +#endregion using System; @@ -31,6 +33,14 @@ namespace OpenTK.Input { /// /// Provides access to GamePad devices. + /// A GamePad device offers a well-defined layout with + /// one direction-pad, two thumbsticks, two triggers, + /// four main buttons (A, B, X, Y) and up to seven + /// auxilliary buttons. + /// Use GetCapabilities to retrieve the exact + /// capabilities of a given device. + /// Use GetState to retrieve the current state + /// of a given device. /// public sealed class GamePad { diff --git a/Source/OpenTK/Input/GamePadButtons.cs b/Source/OpenTK/Input/GamePadButtons.cs index c13a9f0c..676fb1f9 100644 --- a/Source/OpenTK/Input/GamePadButtons.cs +++ b/Source/OpenTK/Input/GamePadButtons.cs @@ -1,11 +1,11 @@ -// #region License +#region License // // GamePadButtons.cs // // Author: // Stefanos A. // -// Copyright (c) 2006-2013 Stefanos Apostolopoulos +// 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 @@ -25,16 +25,23 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // -// #endregion +#endregion + using System; namespace OpenTK.Input { - + /// + /// Describes the of . + /// public struct GamePadButtons : IEquatable { Buttons buttons; + /// + /// Initializes a new instance of the structure. + /// + /// A bitmask containing the button state. public GamePadButtons(Buttons state) { buttons = state; @@ -42,81 +49,136 @@ namespace OpenTK.Input #region Public Members + /// + /// Gets the for the A button. + /// public ButtonState A { get { return GetButton(Buttons.A); } } + /// + /// Gets the for the B button. + /// public ButtonState B { get { return GetButton(Buttons.B); } } + /// + /// Gets the for the X button. + /// public ButtonState X { get { return GetButton(Buttons.X); } } + /// + /// Gets the for the Y button. + /// public ButtonState Y { get { return GetButton(Buttons.Y); } } + /// + /// Gets the for the Back button. + /// public ButtonState Back { get { return GetButton(Buttons.Back); } } + /// + /// Gets the for the big button. + /// This button is also known as Home or Guide. + /// public ButtonState BigButton { get { return GetButton(Buttons.BigButton); } } + /// + /// Gets the for the left shoulder button. + /// public ButtonState LeftShoulder { get { return GetButton(Buttons.LeftShoulder); } } + /// + /// Gets the for the left stick button. + /// This button represents a left stick that is pressed in. + /// public ButtonState LeftStick { get { return GetButton(Buttons.LeftStick); } } + /// + /// Gets the for the right shoulder button. + /// public ButtonState RightShoulder { get { return GetButton(Buttons.RightShoulder); } } + /// + /// Gets the for the right stick button. + /// This button represents a right stick that is pressed in. + /// public ButtonState RightStick { get { return GetButton(Buttons.RightStick); } } + /// + /// Gets the for the starth button. + /// public ButtonState Start { get { return GetButton(Buttons.Start); } } + /// A instance to test for equality. + /// A instance to test for equality. public static bool operator ==(GamePadButtons left, GamePadButtons right) { return left.Equals(right); } + /// A instance to test for inequality. + /// A instance to test for inequality. public static bool operator !=(GamePadButtons left, GamePadButtons right) { return !left.Equals(right); } + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { return Convert.ToString((int)buttons, 2).PadLeft(10, '0'); } + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. public override int GetHashCode() { return buttons.GetHashCode(); } + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals(object obj) { return @@ -128,6 +190,12 @@ namespace OpenTK.Input #region IEquatable Members + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals(GamePadButtons other) { return buttons == other.buttons; diff --git a/Source/OpenTK/Input/GamePadDPad.cs b/Source/OpenTK/Input/GamePadDPad.cs index 8e1a0588..d05300ef 100644 --- a/Source/OpenTK/Input/GamePadDPad.cs +++ b/Source/OpenTK/Input/GamePadDPad.cs @@ -31,7 +31,9 @@ using System; namespace OpenTK.Input { - + /// + /// Describes the state of a directional pad. + /// public struct GamePadDPad : IEquatable { [Flags] @@ -45,7 +47,7 @@ namespace OpenTK.Input DPadButtons buttons; - #region Public Members + #region Internal Members internal GamePadDPad(Buttons state) { @@ -54,40 +56,104 @@ namespace OpenTK.Input buttons = (DPadButtons)((int)state & 0x0f); } + #endregion + + #region Public Members + + /// + /// Gets the for the up button. + /// + /// ButtonState.Pressed if the up button is pressed; otherwise, ButtonState.Released. + public ButtonState Up + { + get { return IsUp ? ButtonState.Pressed : ButtonState.Released; } + } + + /// + /// Gets the for the down button. + /// + /// ButtonState.Pressed if the down button is pressed; otherwise, ButtonState.Released. + public ButtonState Down + { + get { return IsDown ? ButtonState.Pressed : ButtonState.Released; } + } + + /// + /// Gets the for the left button. + /// + /// ButtonState.Pressed if the left button is pressed; otherwise, ButtonState.Released. + public ButtonState Left + { + get { return IsLeft ? ButtonState.Pressed : ButtonState.Released; } + } + + /// + /// Gets the for the right button. + /// + /// ButtonState.Pressed if the right button is pressed; otherwise, ButtonState.Released. + public ButtonState Right + { + get { return IsRight ? ButtonState.Pressed : ButtonState.Released; } + } + + /// + /// Gets a value indicating whether the up button is pressed. + /// + /// true if the up button is pressed; otherwise, false. public bool IsUp { get { return (buttons & DPadButtons.Up) != 0; } internal set { SetButton(DPadButtons.Up, value); } } + /// + /// Gets a value indicating whether the down button is pressed. + /// + /// true if the down button is pressed; otherwise, false. public bool IsDown { get { return (buttons & DPadButtons.Down) != 0; } internal set { SetButton(DPadButtons.Down, value); } } + /// + /// Gets a value indicating whether the left button is pressed. + /// + /// true if the left button is pressed; otherwise, false. public bool IsLeft { get { return (buttons & DPadButtons.Left) != 0; } internal set { SetButton(DPadButtons.Left, value); } } + /// + /// Gets a value indicating whether the right button is pressed. + /// + /// true if the right button is pressed; otherwise, false. public bool IsRight { get { return (buttons & DPadButtons.Right) != 0; } internal set { SetButton(DPadButtons.Right, value); } } + /// A instance to test for equality. + /// A instance to test for equality. public static bool operator ==(GamePadDPad left, GamePadDPad right) { return left.Equals(right); } + /// A instance to test for inequality. + /// A instance to test for inequality. public static bool operator !=(GamePadDPad left, GamePadDPad right) { return !left.Equals(right); } + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { return String.Format( @@ -98,11 +164,22 @@ namespace OpenTK.Input IsRight ? "R" : String.Empty); } + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. public override int GetHashCode() { return buttons.GetHashCode(); } + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals(object obj) { return @@ -130,6 +207,12 @@ namespace OpenTK.Input #region IEquatable Members + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals(GamePadDPad other) { return buttons == other.buttons; diff --git a/Source/OpenTK/Input/GamePadState.cs b/Source/OpenTK/Input/GamePadState.cs index 60318dae..7d0f0630 100644 --- a/Source/OpenTK/Input/GamePadState.cs +++ b/Source/OpenTK/Input/GamePadState.cs @@ -30,7 +30,7 @@ using System; namespace OpenTK.Input { /// - /// Encapsulates the state of a GamePad device. + /// Describes the current state of a device. /// public struct GamePadState : IEquatable { @@ -48,36 +48,65 @@ namespace OpenTK.Input #region Public Members + /// + /// Gets a structure describing the + /// state of the GamePad thumb sticks. + /// public GamePadThumbSticks ThumbSticks { get { return new GamePadThumbSticks(left_stick_x, left_stick_y, right_stick_x, right_stick_y); } } + /// + /// Gets a structure describing the + /// state of the GamePad buttons. + /// public GamePadButtons Buttons { get { return new GamePadButtons(buttons); } } + /// + /// Gets a structure describing the + /// state of the GamePad directional pad. + /// public GamePadDPad DPad { get { return new GamePadDPad(buttons); } } + /// + /// Gets a structure describing the + /// state of the GamePad triggers. + /// public GamePadTriggers Triggers { get { return new GamePadTriggers(left_trigger, right_trigger); } } + /// + /// Gets a value indicating whether this GamePad instance is connected. + /// + /// true if this instance is connected; otherwise, false. public bool IsConnected { get { return is_connected; } } + /// + /// Gets the packet number for this GamePadState instance. + /// Use the packet number to determine whether the state of a + /// GamePad device has changed. + /// public int PacketNumber { get { return packet_number; } } + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { return String.Format( @@ -85,6 +114,11 @@ namespace OpenTK.Input ThumbSticks, Buttons, DPad, IsConnected); } + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. public override int GetHashCode() { return @@ -92,6 +126,12 @@ namespace OpenTK.Input DPad.GetHashCode() ^ IsConnected.GetHashCode(); } + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals(object obj) { return @@ -102,6 +142,13 @@ namespace OpenTK.Input #endregion #region IEquatable Members + + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals(GamePadState other) { return diff --git a/Source/OpenTK/Input/GamePadThumbSticks.cs b/Source/OpenTK/Input/GamePadThumbSticks.cs index 63838c6f..42fd2c0f 100644 --- a/Source/OpenTK/Input/GamePadThumbSticks.cs +++ b/Source/OpenTK/Input/GamePadThumbSticks.cs @@ -1,4 +1,4 @@ -// #region License +#region License // // GamePadThumbSticks.cs // @@ -25,13 +25,15 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // -// #endregion - +#endregion using System; namespace OpenTK.Input { + /// + /// Describes the current thumb stick state of a device + /// public struct GamePadThumbSticks : IEquatable { const float ConversionFactor = 1.0f / short.MaxValue; @@ -50,26 +52,40 @@ namespace OpenTK.Input #region Public Members + /// + /// Gets a describing the state of the left thumb stick. + /// public Vector2 Left { get { return new Vector2(left_x * ConversionFactor, left_y * ConversionFactor); } } + /// + /// Gets a describing the state of the right thumb stick. + /// public Vector2 Right { get { return new Vector2(right_x * ConversionFactor, right_y * ConversionFactor); } } + /// A instance to test for equality. + /// A instance to test for equality. public static bool operator ==(GamePadThumbSticks left, GamePadThumbSticks right) { return left.Equals(right); } + /// A instance to test for inequality. + /// A instance to test for inequality. public static bool operator !=(GamePadThumbSticks left, GamePadThumbSticks right) { return !left.Equals(right); } + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { return String.Format( @@ -77,6 +93,11 @@ namespace OpenTK.Input Left.X, Left.Y, Right.X, Right.Y); } + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. public override int GetHashCode() { return @@ -84,6 +105,12 @@ namespace OpenTK.Input right_x.GetHashCode() ^ right_y.GetHashCode(); } + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals(object obj) { return @@ -95,6 +122,12 @@ namespace OpenTK.Input #region IEquatable Members + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals(GamePadThumbSticks other) { return diff --git a/Source/OpenTK/Input/GamePadTriggers.cs b/Source/OpenTK/Input/GamePadTriggers.cs index 0e505d81..df9df1a7 100644 --- a/Source/OpenTK/Input/GamePadTriggers.cs +++ b/Source/OpenTK/Input/GamePadTriggers.cs @@ -32,6 +32,9 @@ using System; namespace OpenTK.Input { + /// + /// Describes the state of a trigger buttons. + /// public struct GamePadTriggers : IEquatable { const float ConversionFactor = 1.0f / short.MaxValue; @@ -46,26 +49,40 @@ namespace OpenTK.Input #region Public Members + /// + /// Gets the offset of the left trigger button, between 0.0 and 1.0. + /// public float Left { get { return left * ConversionFactor; } } + /// + /// Gets the offset of the left trigger button, between 0.0 and 1.0. + /// public float Right { get { return right * ConversionFactor; } } + /// A instance to test for equality. + /// A instance to test for equality. public static bool operator ==(GamePadTriggers left, GamePadTriggers right) { return left.Equals(right); } + /// A instance to test for equality. + /// A instance to test for equality. public static bool operator !=(GamePadTriggers left, GamePadTriggers right) { return !left.Equals(right); } + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { return String.Format( @@ -73,12 +90,23 @@ namespace OpenTK.Input Left, Right); } + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. public override int GetHashCode() { return left.GetHashCode() ^ right.GetHashCode(); } + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals(object obj) { return @@ -90,6 +118,12 @@ namespace OpenTK.Input #region IEquatable Members + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals(GamePadTriggers other) { return diff --git a/Source/OpenTK/Input/GamePadType.cs b/Source/OpenTK/Input/GamePadType.cs index 37311627..1464117f 100644 --- a/Source/OpenTK/Input/GamePadType.cs +++ b/Source/OpenTK/Input/GamePadType.cs @@ -29,19 +29,69 @@ namespace OpenTK.Input { + /// + /// Enumerates available types. + /// public enum GamePadType { + /// + /// The GamePad is of an unknown type. + /// Unknown = 0, + + /// + /// The GamePad is an arcade stick. + /// ArcadeStick, + + /// + /// The GamePad is a dance pad. + /// DancePad, + + /// + /// The GamePad is a flight stick. + /// FlightStick, + + /// + /// The GamePad is a guitar. + /// Guitar, + + /// + /// The GamePad is a driving wheel. + /// Wheel, + + /// + /// The GamePad is an alternate guitar. + /// AlternateGuitar, + + /// + /// The GamePad is a big button pad. + /// BigButtonPad, + + /// + /// The GamePad is a drum kit. + /// DrumKit, + + /// + /// The GamePad is a game pad. + /// GamePad, + + /// + /// The GamePad is an arcade pad. + /// ArcadePad, + + /// + /// The GamePad is a bass guitar. + /// BassGuitar, } } diff --git a/Source/OpenTK/Input/Joystick.cs b/Source/OpenTK/Input/Joystick.cs index 7f1037e1..d280815c 100644 --- a/Source/OpenTK/Input/Joystick.cs +++ b/Source/OpenTK/Input/Joystick.cs @@ -33,6 +33,14 @@ using System.Text; namespace OpenTK.Input { + /// + /// Provides access to Joystick devices. + /// Joystick devices provide a varying number of axes and buttons. + /// Use GetCapabilities to retrieve the number of supported + /// axes and buttons on a given device. + /// Use GetState to retrieve the current state of a given device. + /// + /// public sealed class Joystick { static readonly IJoystickDriver2 implementation = @@ -40,11 +48,32 @@ namespace OpenTK.Input private Joystick() { } + /// + /// Retrieves the of the device connected + /// at the specified index. + /// + /// + /// A structure describing + /// the capabilities of the device at the specified index. + /// If no device is connected at the specified index, the IsConnected + /// property of the returned structure will be false. + /// + /// The zero-based index of the device to poll. public static JoystickCapabilities GetCapabilities(int index) { return implementation.GetCapabilities(index); } + /// + /// Retrieves the of the device connected + /// at the specified index. + /// + /// A structure describing + /// the current state of the device at the specified index. + /// If no device is connected at this index, the IsConnected + /// property of the returned structure will be false. + /// + /// The zero-based index of the device to poll. public static JoystickState GetState(int index) { return implementation.GetState(index); diff --git a/Source/OpenTK/Input/JoystickCapabilities.cs b/Source/OpenTK/Input/JoystickCapabilities.cs index 80036211..3bfab7a1 100644 --- a/Source/OpenTK/Input/JoystickCapabilities.cs +++ b/Source/OpenTK/Input/JoystickCapabilities.cs @@ -33,6 +33,9 @@ using System.Text; namespace OpenTK.Input { + /// + /// Describes the JoystickCapabilities of a . + /// public struct JoystickCapabilities : IEquatable { byte axis_count; @@ -42,7 +45,7 @@ namespace OpenTK.Input #region Constructors - public JoystickCapabilities(int axis_count, int button_count, bool is_connected) + internal JoystickCapabilities(int axis_count, int button_count, bool is_connected) { if (axis_count < 0 || axis_count >= JoystickState.MaxAxes) throw new ArgumentOutOfRangeException("axis_count"); @@ -59,21 +62,35 @@ namespace OpenTK.Input #region Public Members + /// + /// Gets the number of axes supported by this . + /// public int AxisCount { get { return axis_count; } } + /// + /// Gets the number of buttons supported by this . + /// public int ButtonCount { get { return button_count; } } + /// + /// Gets a value indicating whether this is connected. + /// + /// true if this instance is connected; otherwise, false. public bool IsConnected { get { return is_connected; } } + /// + /// Returns a that represents the current . + /// + /// A that represents the current . public override string ToString() { return String.Format( @@ -81,6 +98,11 @@ namespace OpenTK.Input AxisCount, ButtonCount, IsConnected); } + /// + /// Serves as a hash function for a object. + /// + /// A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a + /// hash table. public override int GetHashCode() { return @@ -89,6 +111,12 @@ namespace OpenTK.Input IsConnected.GetHashCode(); } + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public override bool Equals(object obj) { return @@ -109,6 +137,12 @@ namespace OpenTK.Input #region IEquatable Members + /// + /// Determines whether the specified is equal to the current . + /// + /// The to compare with the current . + /// true if the specified is equal to the current + /// ; otherwise, false. public bool Equals(JoystickCapabilities other) { return From 53552b0070d6573bf3b43f70588fd1eccb08b384 Mon Sep 17 00:00:00 2001 From: thefiddler Date: Fri, 3 Jan 2014 02:17:42 +0100 Subject: [PATCH 154/154] [Input] Corrected malformed documentation comments --- Source/OpenTK/Input/GamePad.cs | 2 +- Source/OpenTK/Input/JoystickState.cs | 7 +++---- Source/OpenTK/Platform/SDL2/Sdl2.cs | 2 +- Source/OpenTK/ToolkitOptions.cs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Source/OpenTK/Input/GamePad.cs b/Source/OpenTK/Input/GamePad.cs index 11213597..7578eb23 100644 --- a/Source/OpenTK/Input/GamePad.cs +++ b/Source/OpenTK/Input/GamePad.cs @@ -1,6 +1,6 @@ #region License // -// GamePadButtons.cs +// GamePad.cs // // Author: // Stefanos A. diff --git a/Source/OpenTK/Input/JoystickState.cs b/Source/OpenTK/Input/JoystickState.cs index f00a5521..f5f533a2 100644 --- a/Source/OpenTK/Input/JoystickState.cs +++ b/Source/OpenTK/Input/JoystickState.cs @@ -5,7 +5,7 @@ // Author: // Stefanos A. // -// Copyright (c) 2006-2013 Stefanos Apostolopoulos +// 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 @@ -28,7 +28,6 @@ #endregion using System; -using System.Collections.Generic; using System.Diagnostics; using System.Text; @@ -57,8 +56,8 @@ namespace OpenTK.Input /// Gets a value between -1.0 and 1.0 representing the current offset of the specified . /// /// - /// A value between -1.0 and 1.0 representing offset of the specified + /// A value between -1.0 and 1.0 representing offset of the specified . + /// If the specified axis does not exist, then the return value is 0.0. Use /// to query the number of available axes. /// /// The to query. diff --git a/Source/OpenTK/Platform/SDL2/Sdl2.cs b/Source/OpenTK/Platform/SDL2/Sdl2.cs index 38ebef43..7989410b 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2.cs @@ -140,7 +140,7 @@ namespace OpenTK.Platform.SDL2 /// Gets the SDL joystick layer binding for the specified game controller button /// /// Pointer to a game controller instance returned by GameControllerOpen. - /// A value from the GameControllerButton enumeration + /// A value from the GameControllerButton enumeration /// A GameControllerButtonBind instance describing the specified binding [SuppressUnmanagedCodeSecurity] [DllImport(lib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SDL_GameControllerGetBindForButton", ExactSpelling = true)] diff --git a/Source/OpenTK/ToolkitOptions.cs b/Source/OpenTK/ToolkitOptions.cs index 91a16a9a..5541a2bb 100644 --- a/Source/OpenTK/ToolkitOptions.cs +++ b/Source/OpenTK/ToolkitOptions.cs @@ -84,7 +84,7 @@ namespace OpenTK /// Set to false for applications that are not /// DPI-aware (e.g. WinForms.) /// - /// + /// See: http://msdn.microsoft.com/en-us/library/windows/desktop/ee308410(v=vs.85).aspx public bool EnableHighResolution { get; set; } ///