Merge pull request #114 from thefiddler/nativewindow

INativeWindow cleanup and consolidation
This commit is contained in:
thefiddler 2014-05-12 02:20:29 +02:00
commit cd7342b688
40 changed files with 2387 additions and 1916 deletions

View file

@ -572,6 +572,7 @@
<Link>Dependencies\x64\libSDL2.dylib</Link> <Link>Dependencies\x64\libSDL2.dylib</Link>
</None> </None>
<Compile Include="OpenTK\Test\ExternalContext.cs" /> <Compile Include="OpenTK\Test\ExternalContext.cs" />
<Compile Include="OpenTK\Test\PointToClient.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5"> <BootstrapperPackage Include="Microsoft.Net.Client.3.5">

View file

@ -26,6 +26,28 @@ namespace Examples.Tests
bool mouse_in_window = false; bool mouse_in_window = false;
bool viewport_changed = true; bool viewport_changed = true;
MouseCursor Pencil;
// legacy GameWindow.Mouse.* events
Vector4 mousedevice_pos;
int mousedevice_buttons;
MouseState mousedevice_state;
// new GameWindow.Mouse* events
Vector4 mouse_pos;
int mouse_buttons;
MouseState mouse_state;
// legacy GameWindow.Keyboard.Key* events
Dictionary<Key, int> legacy_keyboard_keys = new Dictionary<Key, int>();
KeyboardState legacy_keyboard_state;
KeyModifiers legacy_keyboard_modifiers;
//new GameWindow.Key* events
Dictionary<Key, int> keyboard_keys = new Dictionary<Key, int>();
KeyboardState keyboard_state;
KeyModifiers keyboard_modifiers;
// time drift // time drift
Stopwatch watch = new Stopwatch(); Stopwatch watch = new Stopwatch();
double update_time, render_time; double update_time, render_time;
@ -42,8 +64,6 @@ namespace Examples.Tests
double variable_refresh_timestep_pos = -1; double variable_refresh_timestep_pos = -1;
double fixed_update_timestep_pos = -1; double fixed_update_timestep_pos = -1;
KeyModifiers modifiers;
public GameWindowStates() public GameWindowStates()
: base(800, 600, GraphicsMode.Default) : base(800, 600, GraphicsMode.Default)
{ {
@ -52,16 +72,26 @@ namespace Examples.Tests
KeyDown += KeyDownHandler; KeyDown += KeyDownHandler;
KeyUp += KeyUpHandler; KeyUp += KeyUpHandler;
KeyPress += KeyPressHandler; KeyPress += KeyPressHandler;
Keyboard.KeyDown += KeyboardDeviceDownHandler;
Keyboard.KeyUp += KeyboardDeviceUpHandler;
MouseEnter += delegate { mouse_in_window = true; }; MouseEnter += delegate { mouse_in_window = true; };
MouseLeave += delegate { mouse_in_window = false; }; MouseLeave += delegate { mouse_in_window = false; };
Mouse.Move += MouseMoveHandler; Mouse.Move += MouseDeviceMoveHandler;
Mouse.ButtonDown += MouseButtonHandler; Mouse.WheelChanged += MouseDeviceWheelHandler;
Mouse.ButtonUp += MouseButtonHandler; Mouse.ButtonDown += MouseDeviceButtonHandler;
Mouse.ButtonUp += MouseDeviceButtonHandler;
MouseMove += MouseMoveHandler;
MouseWheel += MouseWheelHandler;
MouseDown += MouseButtonHandler;
MouseUp += MouseButtonHandler;
} }
private void KeyPressHandler(object sender, KeyPressEventArgs e) #region Keyboard Events
void KeyPressHandler(object sender, KeyPressEventArgs e)
{ {
if (TypedText.Length > 32) if (TypedText.Length > 32)
TypedText.Remove(0, 1); TypedText.Remove(0, 1);
@ -108,26 +138,117 @@ namespace Examples.Tests
case Key.BracketRight: TargetUpdateFrequency++; break; case Key.BracketRight: TargetUpdateFrequency++; break;
case Key.Comma: TargetRenderFrequency--; break; case Key.Comma: TargetRenderFrequency--; break;
case Key.Period: TargetRenderFrequency++; break; case Key.Period: TargetRenderFrequency++; break;
case Key.Space:
CursorVisible = !CursorVisible;
break;
} }
modifiers = e.Modifiers;
if (!keyboard_keys.ContainsKey(e.Key))
{
keyboard_keys.Add(e.Key, 0);
}
keyboard_keys[e.Key] = e.IsRepeat ? 1 : 0;
keyboard_modifiers = e.Modifiers;
keyboard_state = e.Keyboard;
} }
void KeyUpHandler(object sender, KeyboardKeyEventArgs e) void KeyUpHandler(object sender, KeyboardKeyEventArgs e)
{ {
modifiers = e.Modifiers; keyboard_keys.Remove(e.Key);
keyboard_modifiers = e.Modifiers;
keyboard_state = e.Keyboard;
} }
void KeyboardDeviceDownHandler(object sender, KeyboardKeyEventArgs e)
{
if (!legacy_keyboard_keys.ContainsKey(e.Key))
{
legacy_keyboard_keys.Add(e.Key, 0);
}
legacy_keyboard_keys[e.Key] = e.IsRepeat ? 1 : 0;
legacy_keyboard_modifiers = e.Modifiers;
legacy_keyboard_state = e.Keyboard;
}
void KeyboardDeviceUpHandler(object sender, KeyboardKeyEventArgs e)
{
legacy_keyboard_keys.Remove(e.Key);
legacy_keyboard_modifiers = e.Modifiers;
legacy_keyboard_state = e.Keyboard;
}
#endregion
#region MouseDevice events
void MouseDeviceMoveHandler(object sender, MouseMoveEventArgs e)
{
mousedevice_pos.X = e.X;
mousedevice_pos.Y = e.Y;
mousedevice_pos.Z = e.Mouse.Scroll.X;
mousedevice_pos.W = e.Mouse.Scroll.Y;
mousedevice_state = e.Mouse;
}
void MouseDeviceButtonHandler(object sender, MouseButtonEventArgs e)
{
if (e.IsPressed)
{
mousedevice_buttons |= 1 << (int)e.Button;
Cursor = Pencil;
}
else
{
mousedevice_buttons &= ~(1 << (int)e.Button);
Cursor = MouseCursor.Default;
}
mousedevice_state = e.Mouse;
}
void MouseDeviceWheelHandler(object sender, MouseWheelEventArgs e)
{
mousedevice_pos.Z = e.Mouse.Scroll.X;
mousedevice_pos.W = e.Mouse.Scroll.Y;
mousedevice_state = e.Mouse;
}
#endregion
#region Mouse events
void MouseMoveHandler(object sender, MouseMoveEventArgs e) void MouseMoveHandler(object sender, MouseMoveEventArgs e)
{ {
mouse_pos.X = e.X;
mouse_pos.Y = e.Y;
mouse_pos.Z = e.Mouse.Scroll.X;
mouse_pos.W = e.Mouse.Scroll.Y;
mouse_state = e.Mouse;
} }
void MouseButtonHandler(object sender, MouseButtonEventArgs e) void MouseButtonHandler(object sender, MouseButtonEventArgs e)
{ {
if (e.Button == MouseButton.Left && e.IsPressed) if (e.IsPressed)
{ {
CursorVisible = false; mouse_buttons |= 1 << (int)e.Button;
} }
else
{
mouse_buttons &= ~(1 << (int)e.Button);
} }
mouse_state = e.Mouse;
}
void MouseWheelHandler(object sender, MouseWheelEventArgs e)
{
mouse_pos.Z = e.Mouse.Scroll.X;
mouse_pos.W = e.Mouse.Scroll.Y;
mouse_state = e.Mouse;
}
#endregion
#region Private Members
static int Clamp(int val, int min, int max) static int Clamp(int val, int min, int max)
{ {
@ -145,18 +266,8 @@ namespace Examples.Tests
return offset + gfx.MeasureString(str, TextFont).Width; return offset + gfx.MeasureString(str, TextFont).Width;
} }
int DrawKeyboards(Graphics gfx, int line) static void KeyboardStateToString(KeyboardState state, StringBuilder sb)
{ {
line++;
DrawString(gfx, String.Format("Keyboard ({0}):", modifiers), line++);
for (int i = 0; i < 4; i++)
{
var state = OpenTK.Input.Keyboard.GetState(i);
if (state.IsConnected)
{
StringBuilder sb = new StringBuilder();
sb.Append(i);
sb.Append(": ");
for (int key_index = 0; key_index < (int)Key.LastKey; key_index++) for (int key_index = 0; key_index < (int)Key.LastKey; key_index++)
{ {
Key k = (Key)key_index; Key k = (Key)key_index;
@ -166,6 +277,21 @@ namespace Examples.Tests
sb.Append(" "); sb.Append(" ");
} }
} }
}
int DrawKeyboards(Graphics gfx, int line)
{
line++;
DrawString(gfx, "Keyboard:", line++);
for (int i = 0; i < 4; i++)
{
var state = OpenTK.Input.Keyboard.GetState(i);
if (state.IsConnected)
{
StringBuilder sb = new StringBuilder();
sb.Append(i);
sb.Append(": ");
KeyboardStateToString(state, sb);
DrawString(gfx, sb.ToString(), line++); DrawString(gfx, sb.ToString(), line++);
} }
} }
@ -201,6 +327,112 @@ namespace Examples.Tests
return line; return line;
} }
int DrawKeyboardDevice(Graphics gfx, int line)
{
StringBuilder sb = new StringBuilder();
sb.Append("KeyboardDevice: ");
for (Key key = 0; key < Key.LastKey; key++)
{
if (Keyboard[key])
{
sb.Append(key);
sb.Append(" ");
}
}
DrawString(gfx, sb.ToString(), line++);
sb.Remove(0, sb.Length);
sb.Append("KeyboardDevice events: [");
sb.Append(legacy_keyboard_modifiers);
sb.Append("] ");
foreach (var pair in legacy_keyboard_keys)
{
sb.Append(pair.Key);
sb.Append(":");
sb.Append(pair.Value);
sb.Append(" ");
}
DrawString(gfx, sb.ToString(), line++);
sb.Remove(0, sb.Length);
sb.Append("KeyboardDevice state: ");
KeyboardStateToString(legacy_keyboard_state, sb);
DrawString(gfx, sb.ToString(), line++);
sb.Remove(0, sb.Length);
sb.Append("Keyboard events: [");
sb.Append(keyboard_modifiers);
sb.Append("] ");
foreach (var pair in keyboard_keys)
{
sb.Append(pair.Key);
sb.Append(":");
sb.Append(pair.Value);
sb.Append(" ");
}
DrawString(gfx, sb.ToString(), line++);
sb.Remove(0, sb.Length);
sb.Append("Keyboard state: ");
KeyboardStateToString(keyboard_state, sb);
DrawString(gfx, sb.ToString(), line++);
return line;
}
int DrawMouseDevice(Graphics gfx, int line)
{
StringBuilder sb = new StringBuilder();
sb.Append("MouseDevice: ");
sb.AppendFormat("[{0}, {1}, {2:0.00}] ",
Mouse.X, Mouse.Y, Mouse.WheelPrecise);
for (var i = MouseButton.Left; i < MouseButton.LastButton; i++)
{
if (Mouse[i])
{
sb.Append(i);
sb.Append(" ");
}
}
sb.AppendLine();
DrawString(gfx, sb.ToString(), line++);
sb.Remove(0, sb.Length);
sb.Append("MouseDevice events: ");
sb.AppendFormat("[{0}, {1}, {2:0.00}, {3:0.00}] ",
mousedevice_pos.X, mousedevice_pos.Y,
mousedevice_pos.Z, mousedevice_pos.W);
for (var i = MouseButton.Left; i < MouseButton.LastButton; i++)
{
if ((mousedevice_buttons & (1 << (int)i)) != 0)
{
sb.Append(i);
sb.Append(" ");
}
}
sb.Append(" ");
sb.AppendLine(mousedevice_state.ToString());
DrawString(gfx, sb.ToString(), line++);
sb.Remove(0, sb.Length);
sb.Append("Mouse events: ");
sb.AppendFormat("[{0}, {1}, {2:0.00}, {3:0.00}] ",
mouse_pos.X, mouse_pos.Y,
mouse_pos.Z, mouse_pos.W);
for (var i = MouseButton.Left; i < MouseButton.LastButton; i++)
{
if ((mouse_buttons & (1 << (int)i)) != 0)
{
sb.Append(i);
sb.Append(" ");
}
}
sb.Append(" ");
sb.AppendLine(mouse_state.ToString());
DrawString(gfx, sb.ToString(), line++);
return line;
}
static int DrawLegacyJoysticks(Graphics gfx, IList<JoystickDevice> joysticks, int line) static int DrawLegacyJoysticks(Graphics gfx, IList<JoystickDevice> joysticks, int line)
{ {
line++; line++;
@ -236,6 +468,8 @@ namespace Examples.Tests
return line; return line;
} }
#endregion
protected override void OnUpdateFrame(FrameEventArgs e) protected override void OnUpdateFrame(FrameEventArgs e)
{ {
double clock_time = watch.Elapsed.TotalSeconds; double clock_time = watch.Elapsed.TotalSeconds;
@ -267,7 +501,9 @@ namespace Examples.Tests
mouse_in_window ? "inside" : "outside", mouse_in_window ? "inside" : "outside",
CursorVisible ? "visible" : "hidden", CursorVisible ? "visible" : "hidden",
Focused ? "Focused" : "Not focused"), line++); Focused ? "Focused" : "Not focused"), line++);
DrawString(gfx, String.Format("Mouse coordinates: {0}", new Vector3(Mouse.X, Mouse.Y, Mouse.WheelPrecise)), line++);
line = DrawKeyboardDevice(gfx, line);
line = DrawMouseDevice(gfx, line);
// Timing information // Timing information
line++; line++;
@ -350,6 +586,17 @@ namespace Examples.Tests
{ {
watch.Start(); watch.Start();
using (var bitmap = new Bitmap("Data/Textures/cursor.png"))
{
var data = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
Pencil = new OpenTK.MouseCursor(
2, 21, data.Width, data.Height, data.Scan0);
}
GL.ClearColor(Color.MidnightBlue); GL.ClearColor(Color.MidnightBlue);
GL.Enable(EnableCap.Texture2D); GL.Enable(EnableCap.Texture2D);

View file

@ -0,0 +1,37 @@
using System;
using System.Diagnostics;
using System.Drawing;
using OpenTK;
namespace Examples.Tests
{
[Example("PointToClient Test", ExampleCategory.OpenTK, "NativeWindow")]
public class PointToClientTest
{
public static void Main()
{
using (var window = new NativeWindow())
{
Trace.WriteLine(String.Format("Window bounds: {0}", window.Bounds));
Trace.WriteLine(String.Format("Window client: {0}", window.ClientRectangle));
Point pclient = new Point(100, 100);
Point pscreen = window.PointToScreen(pclient);
Point ptest = window.PointToClient(pscreen);
Trace.WriteLine(String.Format("Client: {0} -> Screen: {1} -> Client: {2}",
pclient, pscreen, ptest));
Trace.WriteLine(String.Format("Test {0}",
ptest == pclient ? "succeeded" : "failed"));
pscreen = new Point(100, 100);
pclient = window.PointToClient(pscreen);
ptest = window.PointToScreen(pclient);
Trace.WriteLine(String.Format("Screen: {0} -> Client: {1} -> Screen: {2}",
pscreen, pclient, ptest));
Trace.WriteLine(String.Format("Test {0}",
ptest == pscreen ? "succeeded" : "failed"));
}
}
}
}

View file

@ -51,9 +51,9 @@ namespace OpenTK.Graphics
protected string[] EntryPointNamesInstance; protected string[] EntryPointNamesInstance;
internal protected IntPtr[] _EntryPointsInstance; internal IntPtr[] _EntryPointsInstance;
internal protected byte[] _EntryPointNamesInstance; internal byte[] _EntryPointNamesInstance;
internal protected int[] _EntryPointNameOffsetsInstance; internal int[] _EntryPointNameOffsetsInstance;
/// <summary> /// <summary>
/// Retrieves an unmanaged function pointer to the specified function. /// Retrieves an unmanaged function pointer to the specified function.

View file

@ -260,10 +260,26 @@ namespace OpenTK
/// </summary> /// </summary>
event EventHandler<EventArgs> MouseEnter; event EventHandler<EventArgs> MouseEnter;
//event EventHandler<MouseEventArgs> MouseMove; /// <summary>
//event EventHandler<MouseEventArgs> MouseWheel; /// Occurs whenever a <see cref="MouseButton"/> is clicked.
//event EventHandler<MouseEventArgs> MouseDown; /// </summary>
//event EventHandler<MouseEventArgs> MouseUp; event EventHandler<Input.MouseButtonEventArgs> MouseDown;
/// <summary>
/// Occurs whenever a <see cref="MouseButton"/> is released.
/// </summary>
event EventHandler<Input.MouseButtonEventArgs> MouseUp;
/// <summary>
/// Occurs whenever the mouse cursor is moved;
/// </summary>
event EventHandler<Input.MouseMoveEventArgs> MouseMove;
/// <summary>
/// Occurs whenever a mouse wheel is moved;
/// </summary>
event EventHandler<Input.MouseWheelEventArgs> MouseWheel;
//event EventHandler<MouseEventArgs> MouseClick; //event EventHandler<MouseEventArgs> MouseClick;
//event EventHandler<MouseEventArgs> MouseDoubleClick; //event EventHandler<MouseEventArgs> MouseDoubleClick;

View file

@ -21,13 +21,11 @@ namespace OpenTK.Input
public sealed class KeyboardDevice : IInputDevice public sealed class KeyboardDevice : IInputDevice
{ {
//private IKeyboard keyboard; //private IKeyboard keyboard;
private bool[] keys = new bool[(int)Key.LastKey];
private bool[] scancodes = new bool[256];
private string description; private string description;
private int numKeys, numFKeys, numLeds; private int numKeys, numFKeys, numLeds;
private IntPtr devID; private IntPtr devID;
private bool repeat; private bool repeat;
private KeyboardKeyEventArgs args = new KeyboardKeyEventArgs(); private KeyboardState state;
#region --- Constructors --- #region --- Constructors ---
@ -44,7 +42,7 @@ namespace OpenTK.Input
/// <returns>True if the Key is pressed, false otherwise.</returns> /// <returns>True if the Key is pressed, false otherwise.</returns>
public bool this[Key key] public bool this[Key key]
{ {
get { return keys[(int)key]; } get { return state[key]; }
} }
/// <summary> /// <summary>
@ -52,9 +50,10 @@ namespace OpenTK.Input
/// </summary> /// </summary>
/// <param name="scancode">The scancode to check.</param> /// <param name="scancode">The scancode to check.</param>
/// <returns>True if the scancode is pressed, false otherwise.</returns> /// <returns>True if the scancode is pressed, false otherwise.</returns>
[CLSCompliant(false)]
public bool this[uint scancode] public bool this[uint scancode]
{ {
get { return scancodes[scancode]; } get { return scancode < (uint)Key.LastKey && state[(Key)scancode]; }
} }
/// <summary> /// <summary>
@ -124,7 +123,7 @@ namespace OpenTK.Input
/// <summary> /// <summary>
/// Occurs when a key is pressed. /// Occurs when a key is pressed.
/// </summary> /// </summary>
public event EventHandler<KeyboardKeyEventArgs> KeyDown; public event EventHandler<KeyboardKeyEventArgs> KeyDown = delegate { };
#endregion #endregion
@ -133,7 +132,7 @@ namespace OpenTK.Input
/// <summary> /// <summary>
/// Occurs when a key is released. /// Occurs when a key is released.
/// </summary> /// </summary>
public event EventHandler<KeyboardKeyEventArgs> KeyUp; public event EventHandler<KeyboardKeyEventArgs> KeyUp = delegate { };
#endregion #endregion
@ -185,21 +184,22 @@ namespace OpenTK.Input
#region --- Internal Methods --- #region --- Internal Methods ---
#region internal void ClearKeys() internal void HandleKeyDown(object sender, KeyboardKeyEventArgs e)
internal void ClearKeys()
{ {
for (int i = 0; i < keys.Length; i++) state = e.Keyboard;
keys[i] = false; KeyDown(this, e);
for (uint i = 0; i < scancodes.Length; i++)
scancodes[i] = false;
} }
#endregion internal void HandleKeyUp(object sender, KeyboardKeyEventArgs e)
internal void SetKey(Key key, uint scancode, bool state)
{ {
if (keys[(int)key] != state || KeyRepeat) state = e.Keyboard;
KeyUp(this, e);
}
#if false
internal void SetKey(Key key, uint scancode, KeyModifiers mods, bool pressed)
{
if (state[key] != pressed || KeyRepeat)
{ {
// limit scancode to 8bits, otherwise the assignment // limit scancode to 8bits, otherwise the assignment
// below will crash randomly // below will crash randomly
@ -209,42 +209,22 @@ namespace OpenTK.Input
if (state && KeyDown != null) if (state && KeyDown != null)
{ {
args.Key = key; args.Key = key;
args.ScanCode = scancode; args.ScanCode = scancode;
args.Modifiers = GetModifiers(); args.Modifiers = mods;
KeyDown(this, args); KeyDown(this, args);
} }
else if (!state && KeyUp != null) else if (!state && KeyUp != null)
{ {
args.Key = key; args.Key = key;
args.ScanCode = scancode; args.ScanCode = scancode;
args.Modifiers = GetModifiers(); args.Modifiers = mods;
KeyUp(this, args); KeyUp(this, args);
} }
} }
} }
#endif
internal KeyModifiers GetModifiers()
{
KeyModifiers mods = 0;
if (this[Key.AltLeft] || this[Key.AltRight])
{
mods |= KeyModifiers.Alt;
}
if (this[Key.ControlLeft] || this[Key.ControlRight])
{
mods |= KeyModifiers.Control;
}
if (this[Key.ShiftLeft] || this[Key.ShiftRight])
{
mods |= KeyModifiers.Shift;
}
return mods;
}
#endregion #endregion
} }

View file

@ -46,8 +46,8 @@ namespace OpenTK.Input
#region Fields #region Fields
Key key; Key key;
KeyModifiers mods; bool repeat;
uint scancode; KeyboardState state;
#endregion #endregion
@ -65,7 +65,6 @@ namespace OpenTK.Input
public KeyboardKeyEventArgs(KeyboardKeyEventArgs args) public KeyboardKeyEventArgs(KeyboardKeyEventArgs args)
{ {
Key = args.Key; Key = args.Key;
ScanCode = args.ScanCode;
} }
#endregion #endregion
@ -87,8 +86,7 @@ namespace OpenTK.Input
[CLSCompliant(false)] [CLSCompliant(false)]
public uint ScanCode public uint ScanCode
{ {
get { return scancode; } get { return (uint)Key; }
internal set { scancode = value; }
} }
/// <summary> /// <summary>
@ -97,7 +95,7 @@ namespace OpenTK.Input
/// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value> /// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value>
public bool Alt public bool Alt
{ {
get { return (mods & KeyModifiers.Alt) != 0; } get { return state[Key.AltLeft] || state[Key.AltRight]; }
} }
/// <summary> /// <summary>
@ -106,7 +104,7 @@ namespace OpenTK.Input
/// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value> /// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value>
public bool Control public bool Control
{ {
get { return (mods & KeyModifiers.Control) != 0; } get { return state[Key.ControlLeft] || state[Key.ControlRight]; }
} }
/// <summary> /// <summary>
@ -115,7 +113,7 @@ namespace OpenTK.Input
/// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value> /// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value>
public bool Shift public bool Shift
{ {
get { return (mods & KeyModifiers.Shift) != 0; } get { return state[Key.ShiftLeft] || state[Key.ShiftRight]; }
} }
/// <summary> /// <summary>
@ -125,8 +123,39 @@ namespace OpenTK.Input
/// <value>The modifiers.</value> /// <value>The modifiers.</value>
public KeyModifiers Modifiers public KeyModifiers Modifiers
{ {
get { return mods; } get
internal set { mods = value; } {
KeyModifiers mods = 0;
mods |= Alt ? KeyModifiers.Alt : 0;
mods |= Control ? KeyModifiers.Control : 0;
mods |= Shift ? KeyModifiers.Shift : 0;
return mods;
}
}
/// <summary>
/// Gets the current <see cref="OpenTK.Input.KeyboardState"/>.
/// </summary>
/// <value>The keyboard.</value>
public KeyboardState Keyboard
{
get { return state; }
internal set { state = value; }
}
/// <summary>
/// Gets a <see cref="System.Boolean"/> indicating whether
/// this key event is a repeat.
/// </summary>
/// <value>
/// true, if this event was caused by the user holding down
/// a key; false, if this was caused by the user pressing a
/// key for the first time.
/// </value>
public bool IsRepeat
{
get { return repeat; }
internal set { repeat = value; }
} }
#endregion #endregion

View file

@ -43,9 +43,6 @@ namespace OpenTK.Input
const int NumInts = ((int)Key.LastKey + IntSize - 1) / IntSize; const int NumInts = ((int)Key.LastKey + IntSize - 1) / IntSize;
// The following line triggers bogus CS0214 in gmcs 2.0.1, sigh... // The following line triggers bogus CS0214 in gmcs 2.0.1, sigh...
unsafe fixed int Keys[NumInts]; unsafe fixed int Keys[NumInts];
const int CodesSize = 256;
unsafe fixed int Codes[CodesSize];
bool is_connected; bool is_connected;
#endregion #endregion
@ -61,6 +58,7 @@ namespace OpenTK.Input
public bool this[Key key] public bool this[Key key]
{ {
get { return IsKeyDown(key); } get { return IsKeyDown(key); }
internal set { SetKeyState(key, value); }
} }
/// <summary> /// <summary>
@ -71,7 +69,7 @@ namespace OpenTK.Input
/// <returns>True if code is pressed; false otherwise.</returns> /// <returns>True if code is pressed; false otherwise.</returns>
public bool this[short code] public bool this[short code]
{ {
get { return IsKeyDown(code); } get { return IsKeyDown((Key)code); }
} }
/// <summary> /// <summary>
@ -89,7 +87,7 @@ namespace OpenTK.Input
/// <param name="code">The scan code to check.</param> /// <param name="code">The scan code to check.</param>
public bool IsKeyDown(short code) public bool IsKeyDown(short code)
{ {
return ReadBit(code,true); return code >= 0 && code < (short)Key.LastKey && ReadBit(code);
} }
/// <summary> /// <summary>
@ -107,7 +105,7 @@ namespace OpenTK.Input
/// <param name="code">The scan code to check.</param> /// <param name="code">The scan code to check.</param>
public bool IsKeyUp(short code) public bool IsKeyUp(short code)
{ {
return !ReadBit(code,true); return !IsKeyDown(code);
} }
/// <summary> /// <summary>
@ -212,61 +210,50 @@ namespace OpenTK.Input
#region Internal Members #region Internal Members
internal void SetKeyState(Key key, byte code, bool down) internal void SetKeyState(Key key, bool down)
{ {
if (down) if (down)
{ {
EnableBit((int)key); EnableBit((int)key);
EnableBit(code,true);
} }
else else
{ {
DisableBit((int)key); DisableBit((int)key);
DisableBit(code, true);
} }
} }
internal bool ReadBit(int offset, bool ScanCode = false) internal bool ReadBit(int offset)
{ {
ValidateOffset(offset, ScanCode); ValidateOffset(offset);
int int_offset = offset / 32; int int_offset = offset / 32;
int bit_offset = offset % 32; int bit_offset = offset % 32;
unsafe unsafe
{ {
if (ScanCode)
fixed (int* c = Codes) { return (*(c + int_offset) & (1 << bit_offset)) != 0u; }
else
fixed (int* k = Keys) { return (*(k + int_offset) & (1 << bit_offset)) != 0u; } fixed (int* k = Keys) { return (*(k + int_offset) & (1 << bit_offset)) != 0u; }
} }
} }
internal void EnableBit(int offset, bool ScanCode = false) internal void EnableBit(int offset)
{ {
ValidateOffset(offset, ScanCode); ValidateOffset(offset);
int int_offset = offset / 32; int int_offset = offset / 32;
int bit_offset = offset % 32; int bit_offset = offset % 32;
unsafe unsafe
{ {
if (ScanCode)
fixed (int* c = Codes) { *(c + int_offset) |= 1 << bit_offset; }
else
fixed (int* k = Keys) { *(k + int_offset) |= 1 << bit_offset; } fixed (int* k = Keys) { *(k + int_offset) |= 1 << bit_offset; }
} }
} }
internal void DisableBit(int offset, bool ScanCode = false) internal void DisableBit(int offset)
{ {
ValidateOffset(offset, ScanCode); ValidateOffset(offset);
int int_offset = offset / 32; int int_offset = offset / 32;
int bit_offset = offset % 32; int bit_offset = offset % 32;
unsafe unsafe
{ {
if (ScanCode)
fixed (int* c = Codes) { *(c + int_offset) &= ~(1 << bit_offset); }
else
fixed (int* k = Keys) { *(k + int_offset) &= ~(1 << bit_offset); } fixed (int* k = Keys) { *(k + int_offset) &= ~(1 << bit_offset); }
} }
} }
@ -281,12 +268,6 @@ namespace OpenTK.Input
for (int i = 0; i < NumInts; i++) for (int i = 0; i < NumInts; i++)
*(k1 + i) |= *(k2 + i); *(k1 + i) |= *(k2 + i);
} }
int* c2 = other.Codes;
fixed (int* c1 = Codes)
{
for (int i = 0; i < CodesSize; i++)
*(c1 + i) |= *(c2 + i);
}
} }
IsConnected |= other.IsConnected; IsConnected |= other.IsConnected;
} }
@ -300,10 +281,10 @@ namespace OpenTK.Input
#region Private Members #region Private Members
static void ValidateOffset(int offset, bool ScanCode) static void ValidateOffset(int offset)
{ {
if (offset < 0 || offset >= (ScanCode ? 256 : NumInts * IntSize)) if (offset < 0 || offset >= NumInts * IntSize)
throw new ArgumentOutOfRangeException("offset"); throw new ArgumentOutOfRangeException();
} }
#endregion #endregion

View file

@ -48,12 +48,8 @@ namespace OpenTK.Input
string description; string description;
IntPtr id; IntPtr id;
int numButtons, numWheels; int numButtons, numWheels;
readonly bool[] button_state = new bool[Enum.GetValues(typeof(MouseButton)).Length];
float wheel, last_wheel; MouseState state;
Point pos = new Point(), last_pos = new Point();
MouseMoveEventArgs move_args = new MouseMoveEventArgs();
MouseButtonEventArgs button_args = new MouseButtonEventArgs();
MouseWheelEventArgs wheel_args = new MouseWheelEventArgs();
#if COMPAT_REV1519 #if COMPAT_REV1519
int wheel_last_accessed = 0; int wheel_last_accessed = 0;
Point pos_last_accessed = new Point(); Point pos_last_accessed = new Point();
@ -139,8 +135,7 @@ namespace OpenTK.Input
/// </summary> /// </summary>
public int Wheel public int Wheel
{ {
get { return (int)Math.Round(wheel, MidpointRounding.AwayFromZero); } get { return state.Wheel; }
internal set { WheelPrecise = value; }
} }
/// <summary> /// <summary>
@ -148,20 +143,7 @@ namespace OpenTK.Input
/// </summary> /// </summary>
public float WheelPrecise public float WheelPrecise
{ {
get { return wheel; } get { return state.WheelPrecise; }
internal set
{
wheel = value;
wheel_args.X = pos.X;
wheel_args.Y = pos.Y;
wheel_args.ValuePrecise = wheel;
wheel_args.DeltaPrecise = wheel - last_wheel;
WheelChanged(this, wheel_args);
last_wheel = wheel;
}
} }
#endregion #endregion
@ -173,7 +155,7 @@ namespace OpenTK.Input
/// </summary> /// </summary>
public int X public int X
{ {
get { return pos.X; } get { return state.X; }
} }
#endregion #endregion
@ -185,7 +167,7 @@ namespace OpenTK.Input
/// </summary> /// </summary>
public int Y public int Y
{ {
get { return pos.Y; } get { return state.Y; }
} }
#endregion #endregion
@ -201,21 +183,11 @@ namespace OpenTK.Input
{ {
get get
{ {
return button_state[(int)button]; return state[button];
} }
internal set internal set
{ {
bool previous_state = button_state[(int)button]; state[button] = value;
button_state[(int)button] = value;
button_args.X = pos.X;
button_args.Y = pos.Y;
button_args.Button = button;
button_args.IsPressed = value;
if (value && !previous_state)
ButtonDown(this, button_args);
else if (!value && previous_state)
ButtonUp(this, button_args);
} }
} }
@ -225,26 +197,29 @@ namespace OpenTK.Input
#region --- Internal Members --- #region --- Internal Members ---
#region internal Point Position internal void HandleMouseDown(object sender, MouseButtonEventArgs e)
/// <summary>
/// Sets a System.Drawing.Point representing the absolute position of the pointer, in window pixel coordinates.
/// </summary>
internal Point Position
{ {
set state = e.Mouse;
{ ButtonDown(this, e);
pos = value;
move_args.X = pos.X;
move_args.Y = pos.Y;
move_args.XDelta = pos.X - last_pos.X;
move_args.YDelta = pos.Y - last_pos.Y;
Move(this, move_args);
last_pos = pos;
}
} }
#endregion internal void HandleMouseUp(object sender, MouseButtonEventArgs e)
{
state = e.Mouse;
ButtonUp(this, e);
}
internal void HandleMouseMove(object sender, MouseMoveEventArgs e)
{
state = e.Mouse;
Move(this, e);
}
internal void HandleMouseWheel(object sender, MouseWheelEventArgs e)
{
state = e.Mouse;
WheelChanged(this, e);
}
#endregion #endregion
@ -309,8 +284,8 @@ namespace OpenTK.Input
{ {
get get
{ {
int result = (int)Math.Round(wheel - wheel_last_accessed, MidpointRounding.AwayFromZero); int result = (int)Math.Round(state.WheelPrecise - wheel_last_accessed, MidpointRounding.AwayFromZero);
wheel_last_accessed = (int)wheel; wheel_last_accessed = state.Wheel;
return result; return result;
} }
} }
@ -327,8 +302,8 @@ namespace OpenTK.Input
{ {
get get
{ {
int result = pos.X - pos_last_accessed.X; int result = state.X - pos_last_accessed.X;
pos_last_accessed.X = pos.X; pos_last_accessed.X = state.X;
return result; return result;
} }
} }
@ -345,8 +320,8 @@ namespace OpenTK.Input
{ {
get get
{ {
int result = pos.Y - pos_last_accessed.Y; int result = state.Y - pos_last_accessed.Y;
pos_last_accessed.Y = pos.Y; pos_last_accessed.Y = state.Y;
return result; return result;
} }
} }
@ -357,286 +332,4 @@ namespace OpenTK.Input
#endregion #endregion
} }
#region Event Arguments
/// <summary>
/// Defines the event data for <see cref="MouseDevice"/> events.
/// </summary>
/// <remarks>
/// <para>
/// Do not cache instances of this type outside their event handler.
/// If necessary, you can clone an instance using the
/// <see cref="MouseEventArgs(MouseEventArgs)"/> constructor.
/// </para>
/// </remarks>
public class MouseEventArgs : EventArgs
{
#region Fields
int x, y;
#endregion
#region Constructors
/// <summary>
/// Constructs a new instance.
/// </summary>
public MouseEventArgs()
{
}
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
public MouseEventArgs(int x, int y)
{
this.x = x;
this.y = y;
}
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="args">The <see cref="MouseEventArgs"/> instance to clone.</param>
public MouseEventArgs(MouseEventArgs args)
: this(args.x, args.y)
{
}
#endregion
#region Public Members
/// <summary>
/// Gets the X position of the mouse for the event.
/// </summary>
public int X { get { return x; } internal set { x = value; } }
/// <summary>
/// Gets the Y position of the mouse for the event.
/// </summary>
public int Y { get { return y; } internal set { y = value; } }
/// <summary>
/// Gets a System.Drawing.Points representing the location of the mouse for the event.
/// </summary>
public Point Position { get { return new Point(x, y); } }
#endregion
}
/// <summary>
/// Defines the event data for <see cref="MouseDevice.Move"/> events.
/// </summary>
/// <remarks>
/// <para>
/// Do not cache instances of this type outside their event handler.
/// If necessary, you can clone an instance using the
/// <see cref="MouseMoveEventArgs(MouseMoveEventArgs)"/> constructor.
/// </para>
/// </remarks>
public class MouseMoveEventArgs : MouseEventArgs
{
#region Fields
int x_delta, y_delta;
#endregion
#region Constructors
/// <summary>
/// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
/// </summary>
public MouseMoveEventArgs() { }
/// <summary>
/// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <param name="xDelta">The change in X position produced by this event.</param>
/// <param name="yDelta">The change in Y position produced by this event.</param>
public MouseMoveEventArgs(int x, int y, int xDelta, int yDelta)
: base(x, y)
{
XDelta = xDelta;
YDelta = yDelta;
}
/// <summary>
/// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
/// </summary>
/// <param name="args">The <see cref="MouseMoveEventArgs"/> instance to clone.</param>
public MouseMoveEventArgs(MouseMoveEventArgs args)
: this(args.X, args.Y, args.XDelta, args.YDelta)
{
}
#endregion
#region Public Members
/// <summary>
/// Gets the change in X position produced by this event.
/// </summary>
public int XDelta { get { return x_delta; } internal set { x_delta = value; } }
/// <summary>
/// Gets the change in Y position produced by this event.
/// </summary>
public int YDelta { get { return y_delta; } internal set { y_delta = value; } }
#endregion
}
/// <summary>
/// Defines the event data for <see cref="MouseDevice.ButtonDown"/> and <see cref="MouseDevice.ButtonUp"/> events.
/// </summary>
/// <remarks>
/// <para>
/// Do not cache instances of this type outside their event handler.
/// If necessary, you can clone an instance using the
/// <see cref="MouseButtonEventArgs(MouseButtonEventArgs)"/> constructor.
/// </para>
/// </remarks>
public class MouseButtonEventArgs : MouseEventArgs
{
#region Fields
MouseButton button;
bool pressed;
#endregion
#region Constructors
/// <summary>
/// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
/// </summary>
public MouseButtonEventArgs() { }
/// <summary>
/// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <param name="button">The mouse button for the event.</param>
/// <param name="pressed">The current state of the button.</param>
public MouseButtonEventArgs(int x, int y, MouseButton button, bool pressed)
: base(x, y)
{
this.button = button;
this.pressed = pressed;
}
/// <summary>
/// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
/// </summary>
/// <param name="args">The <see cref="MouseButtonEventArgs"/> instance to clone.</param>
public MouseButtonEventArgs(MouseButtonEventArgs args)
: this(args.X, args.Y, args.Button, args.IsPressed)
{
}
#endregion
#region Public Members
/// <summary>
/// The mouse button for the event.
/// </summary>
public MouseButton Button { get { return button; } internal set { button = value; } }
/// <summary>
/// Gets a System.Boolean representing the state of the mouse button for the event.
/// </summary>
public bool IsPressed { get { return pressed; } internal set { pressed = value; } }
#endregion
}
/// <summary>
/// Defines the event data for <see cref="MouseDevice.WheelChanged"/> events.
/// </summary>
/// <remarks>
/// <para>
/// Do not cache instances of this type outside their event handler.
/// If necessary, you can clone an instance using the
/// <see cref="MouseWheelEventArgs(MouseWheelEventArgs)"/> constructor.
/// </para>
/// </remarks>
public class MouseWheelEventArgs : MouseEventArgs
{
#region Fields
float value;
float delta;
#endregion
#region Constructors
/// <summary>
/// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
/// </summary>
public MouseWheelEventArgs() { }
/// <summary>
/// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <param name="value">The value of the wheel.</param>
/// <param name="delta">The change in value of the wheel for this event.</param>
public MouseWheelEventArgs(int x, int y, int value, int delta)
: base(x, y)
{
this.value = value;
this.delta = delta;
}
/// <summary>
/// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
/// </summary>
/// <param name="args">The <see cref="MouseWheelEventArgs"/> instance to clone.</param>
public MouseWheelEventArgs(MouseWheelEventArgs args)
: this(args.X, args.Y, args.Value, args.Delta)
{
}
#endregion
#region Public Members
/// <summary>
/// Gets the value of the wheel in integer units.
/// To support high-precision mice, it is recommended to use <see cref="ValuePrecise"/> instead.
/// </summary>
public int Value { get { return (int)Math.Round(value, MidpointRounding.AwayFromZero); } }
/// <summary>
/// Gets the change in value of the wheel for this event in integer units.
/// To support high-precision mice, it is recommended to use <see cref="DeltaPrecise"/> instead.
/// </summary>
public int Delta { get { return (int)Math.Round(delta, MidpointRounding.AwayFromZero); } }
/// <summary>
/// Gets the precise value of the wheel in floating-point units.
/// </summary>
public float ValuePrecise { get { return value; } internal set { this.value = value; } }
/// <summary>
/// Gets the precise change in value of the wheel for this event in floating-point units.
/// </summary>
public float DeltaPrecise { get { return delta; } internal set { delta = value; } }
#endregion
}
#endregion
} }

View file

@ -0,0 +1,369 @@
#region License
//
// MouseEventArgs.cs
//
// Author:
// Stefanos A. <stapostol@gmail.com>
//
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#endregion
using System;
using System.Drawing;
namespace OpenTK.Input
{
/// <summary>
/// Defines the event data for <see cref="MouseDevice"/> events.
/// </summary>
/// <remarks>
/// <para>
/// Do not cache instances of this type outside their event handler.
/// If necessary, you can clone an instance using the
/// <see cref="MouseEventArgs(MouseEventArgs)"/> constructor.
/// </para>
/// </remarks>
public class MouseEventArgs : EventArgs
{
#region Fields
MouseState state;
#endregion
#region Constructors
/// <summary>
/// Constructs a new instance.
/// </summary>
public MouseEventArgs()
{
state.SetIsConnected(true);
}
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
public MouseEventArgs(int x, int y)
: this()
{
state.X = x;
state.Y = y;
}
/// <summary>
/// Constructs a new instance.
/// </summary>
/// <param name="args">The <see cref="MouseEventArgs"/> instance to clone.</param>
public MouseEventArgs(MouseEventArgs args)
: this(args.X, args.Y)
{
}
#endregion
#region Protected Members
internal void SetButton(MouseButton button, ButtonState state)
{
if (button < 0 || button > MouseButton.LastButton)
throw new ArgumentOutOfRangeException();
switch (state)
{
case ButtonState.Pressed:
this.state.EnableBit((int)button);
break;
case ButtonState.Released:
this.state.DisableBit((int)button);
break;
}
}
internal ButtonState GetButton(MouseButton button)
{
if (button < 0 || button > MouseButton.LastButton)
throw new ArgumentOutOfRangeException();
return
state.ReadBit((int)button) ?
ButtonState.Pressed : ButtonState.Released;
}
#endregion
#region Public Members
/// <summary>
/// Gets the X position of the mouse for the event.
/// </summary>
public int X { get { return state.X; } internal set { state.X = value; } }
/// <summary>
/// Gets the Y position of the mouse for the event.
/// </summary>
public int Y { get { return state.Y; } internal set { state.Y = value; } }
/// <summary>
/// Gets a <see cref="System.Drawing.Point"/> representing the location of the mouse for the event.
/// </summary>
public Point Position
{
get { return new Point(state.X, state.Y); }
set
{
X = value.X;
Y = value.Y;
}
}
/// <summary>
/// Gets the current <see cref="OpenTK.Input.MouseState"/>.
/// </summary>
public MouseState Mouse
{
get { return state; }
internal set { state = value; }
}
#endregion
}
/// <summary>
/// Defines the event data for <see cref="MouseDevice.Move"/> events.
/// </summary>
/// <remarks>
/// <para>
/// Do not cache instances of this type outside their event handler.
/// If necessary, you can clone an instance using the
/// <see cref="MouseMoveEventArgs(MouseMoveEventArgs)"/> constructor.
/// </para>
/// </remarks>
public class MouseMoveEventArgs : MouseEventArgs
{
#region Fields
int x_delta, y_delta;
#endregion
#region Constructors
/// <summary>
/// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
/// </summary>
public MouseMoveEventArgs() { }
/// <summary>
/// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <param name="xDelta">The change in X position produced by this event.</param>
/// <param name="yDelta">The change in Y position produced by this event.</param>
public MouseMoveEventArgs(int x, int y, int xDelta, int yDelta)
: base(x, y)
{
XDelta = xDelta;
YDelta = yDelta;
}
/// <summary>
/// Constructs a new <see cref="MouseMoveEventArgs"/> instance.
/// </summary>
/// <param name="args">The <see cref="MouseMoveEventArgs"/> instance to clone.</param>
public MouseMoveEventArgs(MouseMoveEventArgs args)
: this(args.X, args.Y, args.XDelta, args.YDelta)
{
}
#endregion
#region Public Members
/// <summary>
/// Gets the change in X position produced by this event.
/// </summary>
public int XDelta { get { return x_delta; } internal set { x_delta = value; } }
/// <summary>
/// Gets the change in Y position produced by this event.
/// </summary>
public int YDelta { get { return y_delta; } internal set { y_delta = value; } }
#endregion
}
/// <summary>
/// Defines the event data for <see cref="MouseDevice.ButtonDown"/> and <see cref="MouseDevice.ButtonUp"/> events.
/// </summary>
/// <remarks>
/// <para>
/// Do not cache instances of this type outside their event handler.
/// If necessary, you can clone an instance using the
/// <see cref="MouseButtonEventArgs(MouseButtonEventArgs)"/> constructor.
/// </para>
/// </remarks>
public class MouseButtonEventArgs : MouseEventArgs
{
#region Fields
MouseButton button;
bool pressed;
#endregion
#region Constructors
/// <summary>
/// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
/// </summary>
public MouseButtonEventArgs() { }
/// <summary>
/// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <param name="button">The mouse button for the event.</param>
/// <param name="pressed">The current state of the button.</param>
public MouseButtonEventArgs(int x, int y, MouseButton button, bool pressed)
: base(x, y)
{
this.button = button;
this.pressed = pressed;
}
/// <summary>
/// Constructs a new <see cref="MouseButtonEventArgs"/> instance.
/// </summary>
/// <param name="args">The <see cref="MouseButtonEventArgs"/> instance to clone.</param>
public MouseButtonEventArgs(MouseButtonEventArgs args)
: this(args.X, args.Y, args.Button, args.IsPressed)
{
}
#endregion
#region Public Members
/// <summary>
/// Gets the <see cref="MouseButton"/> that triggered this event.
/// </summary>
public MouseButton Button { get { return button; } internal set { button = value; } }
/// <summary>
/// Gets a System.Boolean representing the state of the mouse button for the event.
/// </summary>
public bool IsPressed
{
get { return GetButton(Button) == ButtonState.Pressed; }
internal set { SetButton(Button, value ? ButtonState.Pressed : ButtonState.Released); }
}
#endregion
}
/// <summary>
/// Defines the event data for <see cref="MouseDevice.WheelChanged"/> events.
/// </summary>
/// <remarks>
/// <para>
/// Do not cache instances of this type outside their event handler.
/// If necessary, you can clone an instance using the
/// <see cref="MouseWheelEventArgs(MouseWheelEventArgs)"/> constructor.
/// </para>
/// </remarks>
public class MouseWheelEventArgs : MouseEventArgs
{
#region Fields
float delta;
#endregion
#region Constructors
/// <summary>
/// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
/// </summary>
public MouseWheelEventArgs() { }
/// <summary>
/// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
/// </summary>
/// <param name="x">The X position.</param>
/// <param name="y">The Y position.</param>
/// <param name="value">The value of the wheel.</param>
/// <param name="delta">The change in value of the wheel for this event.</param>
public MouseWheelEventArgs(int x, int y, int value, int delta)
: base(x, y)
{
Mouse.SetScrollAbsolute(Mouse.Scroll.X, value);
this.delta = delta;
}
/// <summary>
/// Constructs a new <see cref="MouseWheelEventArgs"/> instance.
/// </summary>
/// <param name="args">The <see cref="MouseWheelEventArgs"/> instance to clone.</param>
public MouseWheelEventArgs(MouseWheelEventArgs args)
: this(args.X, args.Y, args.Value, args.Delta)
{
}
#endregion
#region Public Members
/// <summary>
/// Gets the value of the wheel in integer units.
/// To support high-precision mice, it is recommended to use <see cref="ValuePrecise"/> instead.
/// </summary>
public int Value { get { return (int)Math.Round(Mouse.Scroll.Y, MidpointRounding.AwayFromZero); } }
/// <summary>
/// Gets the change in value of the wheel for this event in integer units.
/// To support high-precision mice, it is recommended to use <see cref="DeltaPrecise"/> instead.
/// </summary>
public int Delta { get { return (int)Math.Round(delta, MidpointRounding.AwayFromZero); } }
/// <summary>
/// Gets the precise value of the wheel in floating-point units.
/// </summary>
public float ValuePrecise
{
get { return Mouse.Scroll.Y; }
}
/// <summary>
/// Gets the precise change in value of the wheel for this event in floating-point units.
/// </summary>
public float DeltaPrecise { get { return delta; } internal set { delta = value; } }
#endregion
}
}

View file

@ -0,0 +1,119 @@
#region License
//
// MouseWheel.cs
//
// Author:
// Stefanos A. <stapostol@gmail.com>
//
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#endregion
using System;
namespace OpenTK.Input
{
/// <summary>
/// Represents the state of a mouse wheel.
/// </summary>
public struct MouseScrollWheel : IEquatable<MouseScrollWheel>
{
#region Public Members
/// <summary>
/// Gets the absolute horizontal offset of the wheel,
/// or 0 if no horizontal scroll wheel exists.
/// </summary>
/// <value>The x.</value>
public float X { get; internal set; }
/// <summary>
/// Gets the absolute vertical offset of the wheel,
/// or 0 if no vertical scroll wheel exists.
/// </summary>
/// <value>The y.</value>
public float Y { get; internal set; }
/// <param name="left">A <see cref="MouseScrollWheel"/> instance to test for equality.</param>
/// <param name="right">A <see cref="MouseScrollWheel"/> instance to test for equality.</param>
public static bool operator ==(MouseScrollWheel left, MouseScrollWheel right)
{
return left.Equals(right);
}
/// <param name="left">A <see cref="MouseScrollWheel"/> instance to test for inequality.</param>
/// <param name="right">A <see cref="MouseScrollWheel"/> instance to test for inequality.</param>
public static bool operator !=(MouseScrollWheel left, MouseScrollWheel right)
{
return !left.Equals(right);
}
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
/// </summary>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</returns>
public override string ToString()
{
return string.Format("[X={0:0.00}, Y={1:0.00}]", X, Y);
}
/// <summary>
/// Serves as a hash function for a <see cref="OpenTK.Input.MouseScrollWheel"/> object.
/// </summary>
/// <returns>A hash code for this instance that is suitable for use in hashing algorithms and data structures such as a
/// hash table.</returns>
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
/// <summary>
/// Determines whether the specified <see cref="System.Object"/> is equal to the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
/// </summary>
/// <param name="obj">The <see cref="System.Object"/> to compare with the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</param>
/// <returns><c>true</c> if the specified <see cref="System.Object"/> is equal to the current
/// <see cref="OpenTK.Input.MouseScrollWheel"/>; otherwise, <c>false</c>.</returns>
public override bool Equals(object obj)
{
return
obj is MouseScrollWheel &&
Equals((MouseScrollWheel)obj);
}
#endregion
#region IEquatable Members
/// <summary>
/// Determines whether the specified <see cref="OpenTK.Input.MouseScrollWheel"/> is equal to the current <see cref="OpenTK.Input.MouseScrollWheel"/>.
/// </summary>
/// <param name="other">The <see cref="OpenTK.Input.MouseScrollWheel"/> to compare with the current <see cref="OpenTK.Input.MouseScrollWheel"/>.</param>
/// <returns><c>true</c> if the specified <see cref="OpenTK.Input.MouseScrollWheel"/> is equal to the current
/// <see cref="OpenTK.Input.MouseScrollWheel"/>; otherwise, <c>false</c>.</returns>
public bool Equals(MouseScrollWheel other)
{
return X == other.X && Y == other.Y;
}
#endregion
}
}

View file

@ -38,13 +38,9 @@ namespace OpenTK.Input
{ {
#region Fields #region Fields
// Allocate enough ints to store all mouse buttons
const int IntSize = sizeof(int);
const int NumInts = ((int)MouseButton.LastButton + IntSize - 1) / IntSize;
// The following line triggers bogus CS0214 in gmcs 2.0.1, sigh...
unsafe fixed int Buttons[NumInts];
int x, y; int x, y;
float wheel; MouseScrollWheel scroll;
ushort buttons;
bool is_connected; bool is_connected;
#endregion #endregion
@ -93,7 +89,7 @@ namespace OpenTK.Input
/// </summary> /// </summary>
public int Wheel public int Wheel
{ {
get { return (int)Math.Round(wheel, MidpointRounding.AwayFromZero); } get { return (int)Math.Round(scroll.Y, MidpointRounding.AwayFromZero); }
} }
/// <summary> /// <summary>
@ -101,11 +97,16 @@ namespace OpenTK.Input
/// </summary> /// </summary>
public float WheelPrecise public float WheelPrecise
{ {
get { return wheel; } get { return scroll.Y; }
internal set
{
wheel = value;
} }
/// <summary>
/// Gets a <see cref="OpenTK.Input.MouseScrollWheel"/> instance,
/// representing the current state of the mouse scroll wheel.
/// </summary>
public MouseScrollWheel Scroll
{
get { return scroll; }
} }
/// <summary> /// <summary>
@ -253,13 +254,18 @@ namespace OpenTK.Input
/// </returns> /// </returns>
public override int GetHashCode() public override int GetHashCode()
{ {
unsafe return buttons.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ scroll.GetHashCode();
{
fixed (int* b = Buttons)
{
return b->GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ WheelPrecise.GetHashCode();
}
} }
/// <summary>
/// Returns a <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseState"/>.
/// </summary>
/// <returns>A <see cref="System.String"/> that represents the current <see cref="OpenTK.Input.MouseState"/>.</returns>
public override string ToString()
{
string b = Convert.ToString(buttons, 2).PadLeft(10, '0');
return String.Format("[MouseState: X={0}, Y={1}, Scroll={2}, Buttons={3}, IsConnected={4}]",
X, Y, Scroll, b, IsConnected);
} }
#endregion #endregion
@ -269,78 +275,58 @@ namespace OpenTK.Input
internal bool ReadBit(int offset) internal bool ReadBit(int offset)
{ {
ValidateOffset(offset); ValidateOffset(offset);
return (buttons & (1 << offset)) != 0;
int int_offset = offset / 32;
int bit_offset = offset % 32;
unsafe
{
fixed (int* b = Buttons)
{
return (*(b + int_offset) & (1 << bit_offset)) != 0u;
}
}
} }
internal void EnableBit(int offset) internal void EnableBit(int offset)
{ {
ValidateOffset(offset); ValidateOffset(offset);
buttons |= unchecked((ushort)(1 << offset));
int int_offset = offset / 32;
int bit_offset = offset % 32;
unsafe
{
fixed (int* b = Buttons)
{
*(b + int_offset) |= 1 << bit_offset;
}
}
} }
internal void DisableBit(int offset) internal void DisableBit(int offset)
{ {
ValidateOffset(offset); ValidateOffset(offset);
buttons &= unchecked((ushort)(~(1 << offset)));
int int_offset = offset / 32;
int bit_offset = offset % 32;
unsafe
{
fixed (int* b = Buttons)
{
*(b + int_offset) &= ~(1 << bit_offset);
}
}
} }
internal void MergeBits(MouseState other) internal void MergeBits(MouseState other)
{ {
unsafe buttons |= other.buttons;
{ SetScrollRelative(other.scroll.X, other.scroll.Y);
int* b2 = other.Buttons;
fixed (int* b1 = Buttons)
{
for (int i = 0; i < NumInts; i++)
*(b1 + i) |= *(b2 + i);
}
WheelPrecise += other.WheelPrecise;
X += other.X; X += other.X;
Y += other.Y; Y += other.Y;
IsConnected |= other.IsConnected; IsConnected |= other.IsConnected;
} }
}
internal void SetIsConnected(bool value) internal void SetIsConnected(bool value)
{ {
IsConnected = value; IsConnected = value;
} }
#region Internal Members
internal void SetScrollAbsolute(float x, float y)
{
scroll.X = x;
scroll.Y = y;
}
internal void SetScrollRelative(float x, float y)
{
scroll.X += x;
scroll.Y += y;
}
#endregion
#endregion #endregion
#region Private Members #region Private Members
static void ValidateOffset(int offset) static void ValidateOffset(int offset)
{ {
if (offset < 0 || offset >= NumInts * IntSize) if (offset < 0 || offset >= 16)
throw new ArgumentOutOfRangeException("offset"); throw new ArgumentOutOfRangeException("offset");
} }
@ -355,18 +341,11 @@ namespace OpenTK.Input
/// <returns>True, if both instances are equal; false otherwise.</returns> /// <returns>True, if both instances are equal; false otherwise.</returns>
public bool Equals(MouseState other) public bool Equals(MouseState other)
{ {
bool equal = true; return
unsafe buttons == other.buttons &&
{ X == other.X &&
int* b2 = other.Buttons; Y == other.Y &&
fixed (int* b1 = Buttons) Scroll == other.Scroll;
{
for (int i = 0; equal && i < NumInts; i++)
equal &= *(b1 + i) == *(b2 + i);
}
equal &= X == other.X && Y == other.Y && WheelPrecise == other.WheelPrecise;
}
return equal;
} }
#endregion #endregion

View file

@ -163,12 +163,7 @@ namespace OpenTK
/// </returns> /// </returns>
public Point PointToScreen(Point point) public Point PointToScreen(Point point)
{ {
// Here we use the fact that PointToClient just translates the point, and PointToScreen return implementation.PointToScreen(point);
// should perform the inverse operation.
Point trans = PointToClient(Point.Empty);
point.X -= trans.X;
point.Y -= trans.Y;
return point;
} }
#endregion #endregion
@ -680,6 +675,26 @@ namespace OpenTK
/// </summary> /// </summary>
public event EventHandler<EventArgs> WindowStateChanged = delegate { }; public event EventHandler<EventArgs> WindowStateChanged = delegate { };
/// <summary>
/// Occurs when a <see cref="MouseButton"/> is pressed.
/// </summary>
public event EventHandler<MouseButtonEventArgs> MouseDown = delegate { };
/// <summary>
/// Occurs when a <see cref="MouseButton"/> is released.
/// </summary>
public event EventHandler<MouseButtonEventArgs> MouseUp = delegate { };
/// <summary>
/// Occurs whenever the mouse is moved.
/// </summary>
public event EventHandler<MouseMoveEventArgs> MouseMove = delegate { };
/// <summary>
/// Occurs whenever a mouse wheel is moved;
/// </summary>
public event EventHandler<MouseWheelEventArgs> MouseWheel = delegate { };
#endregion #endregion
#endregion #endregion
@ -902,6 +917,54 @@ namespace OpenTK
#endregion #endregion
/// <summary>
/// Raises the <see cref="MouseDown"/> event.
/// </summary>
/// <param name="e">
/// A <see cref="MouseButtonEventArgs"/> instance carrying mouse state information.
/// The information carried by this instance is only valid within this method body.
/// </param>
protected virtual void OnMouseDown(MouseButtonEventArgs e)
{
MouseDown(this, e);
}
/// <summary>
/// Raises the <see cref="MouseUp"/> event.
/// </summary>
/// <param name="e">
/// A <see cref="MouseButtonEventArgs"/> instance carrying mouse state information.
/// The information carried by this instance is only valid within this method body.
/// </param>
protected virtual void OnMouseUp(MouseButtonEventArgs e)
{
MouseUp(this, e);
}
/// <summary>
/// Raises the <see cref="MouseMove"/> event.
/// </summary>
/// <param name="e">
/// A <see cref="MouseMoveEventArgs"/> instance carrying mouse state information.
/// The information carried by this instance is only valid within this method body.
/// </param>
protected virtual void OnMouseMove(MouseMoveEventArgs e)
{
MouseMove(this, e);
}
/// <summary>
/// Raises the <see cref="MouseWheel"/> event.
/// </summary>
/// <param name="e">
/// A <see cref="MouseWheelEventArgs"/> instance carrying mouse state information.
/// The information carried by this instance is only valid within this method body.
/// </param>
protected virtual void OnMouseWheel(MouseWheelEventArgs e)
{
MouseWheel(this, e);
}
#region OnResize #region OnResize
/// <summary> /// <summary>
@ -1054,6 +1117,11 @@ namespace OpenTK
#endregion #endregion
private void OnMouseDownInternal(object sender, MouseButtonEventArgs e) { OnMouseDown(e); }
private void OnMouseUpInternal(object sender, MouseButtonEventArgs e) { OnMouseUp(e); }
private void OnMouseMoveInternal(object sender, MouseMoveEventArgs e) { OnMouseMove(e); }
private void OnMouseWheelInternal(object sender, MouseWheelEventArgs e) { OnMouseWheel(e); }
#region OnMoveInternal #region OnMoveInternal
private void OnMoveInternal(object sender, EventArgs e) { OnMove(e); } private void OnMoveInternal(object sender, EventArgs e) { OnMove(e); }
@ -1116,6 +1184,10 @@ namespace OpenTK
implementation.KeyUp += OnKeyUpInternal; implementation.KeyUp += OnKeyUpInternal;
implementation.MouseEnter += OnMouseEnterInternal; implementation.MouseEnter += OnMouseEnterInternal;
implementation.MouseLeave += OnMouseLeaveInternal; implementation.MouseLeave += OnMouseLeaveInternal;
implementation.MouseDown += OnMouseDownInternal;
implementation.MouseUp += OnMouseUpInternal;
implementation.MouseMove += OnMouseMoveInternal;
implementation.MouseWheel += OnMouseWheelInternal;
implementation.Move += OnMoveInternal; implementation.Move += OnMoveInternal;
implementation.Resize += OnResizeInternal; implementation.Resize += OnResizeInternal;
implementation.TitleChanged += OnTitleChangedInternal; implementation.TitleChanged += OnTitleChangedInternal;
@ -1136,6 +1208,10 @@ namespace OpenTK
implementation.KeyUp -= OnKeyUpInternal; implementation.KeyUp -= OnKeyUpInternal;
implementation.MouseEnter -= OnMouseEnterInternal; implementation.MouseEnter -= OnMouseEnterInternal;
implementation.MouseLeave -= OnMouseLeaveInternal; implementation.MouseLeave -= OnMouseLeaveInternal;
implementation.MouseDown -= OnMouseDownInternal;
implementation.MouseUp -= OnMouseUpInternal;
implementation.MouseMove -= OnMouseMoveInternal;
implementation.MouseWheel -= OnMouseWheelInternal;
implementation.Move -= OnMoveInternal; implementation.Move -= OnMoveInternal;
implementation.Resize -= OnResizeInternal; implementation.Resize -= OnResizeInternal;
implementation.TitleChanged -= OnTitleChangedInternal; implementation.TitleChanged -= OnTitleChangedInternal;

View file

@ -366,9 +366,6 @@
<Compile Include="Platform\X11\Structs.cs"> <Compile Include="Platform\X11\Structs.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Platform\X11\X11Input.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Platform\X11\X11Factory.cs"> <Compile Include="Platform\X11\X11Factory.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
@ -797,6 +794,9 @@
<Compile Include="Platform\MacOS\Carbon\Cgl.cs" /> <Compile Include="Platform\MacOS\Carbon\Cgl.cs" />
<Compile Include="WindowIcon.cs" /> <Compile Include="WindowIcon.cs" />
<Compile Include="Platform\MacOS\Cocoa\NSBitmapFormat.cs" /> <Compile Include="Platform\MacOS\Cocoa\NSBitmapFormat.cs" />
<Compile Include="Platform\NativeWindowBase.cs" />
<Compile Include="Input\MouseScrollWheel.cs" />
<Compile Include="Input\MouseEventArgs.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>

View file

@ -42,18 +42,33 @@ namespace OpenTK.Platform
readonly LegacyJoystickDriver JoystickDriver = new LegacyJoystickDriver(); readonly LegacyJoystickDriver JoystickDriver = new LegacyJoystickDriver();
internal LegacyInputDriver() internal LegacyInputDriver(INativeWindow window)
{ {
dummy_mice_list.Add(new MouseDevice()); if (window == null)
Mouse[0].Description = "Standard Mouse"; throw new ArgumentNullException();
Mouse[0].NumberOfButtons = 3;
Mouse[0].NumberOfWheels = 1;
dummy_keyboard_list.Add(new KeyboardDevice()); var mouse = new MouseDevice();
Keyboard[0].Description = "Standard Keyboard"; mouse.Description = "Standard Mouse";
Keyboard[0].NumberOfKeys = 101; mouse.NumberOfButtons = 3;
Keyboard[0].NumberOfLeds = 3; mouse.NumberOfWheels = 1;
Keyboard[0].NumberOfFunctionKeys = 12; dummy_mice_list.Add(mouse);
var keyboard = new KeyboardDevice();
keyboard.Description = "Standard Keyboard";
keyboard.NumberOfKeys = 101;
keyboard.NumberOfLeds = 3;
keyboard.NumberOfFunctionKeys = 12;
dummy_keyboard_list.Add(keyboard);
// Hook mouse events
window.MouseDown += mouse.HandleMouseDown;
window.MouseUp += mouse.HandleMouseUp;
window.MouseMove += mouse.HandleMouseMove;
window.MouseWheel += mouse.HandleMouseWheel;
// Hook keyboard events
window.KeyDown += keyboard.HandleKeyDown;
window.KeyUp += keyboard.HandleKeyUp;
} }
#region IInputDriver Members #region IInputDriver Members

View file

@ -29,7 +29,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
namespace OpenTK.Platform.MacOS.Carbon namespace OpenTK.Platform.MacOS
{ {
// //
// http://web.archive.org/web/20100501161453/http://www.classicteck.com/rbarticles/mackeyboard.php // http://web.archive.org/web/20100501161453/http://www.classicteck.com/rbarticles/mackeyboard.php

View file

@ -35,6 +35,11 @@ namespace OpenTK.Platform.MacOS
{ {
static class Class static class Class
{ {
public static readonly IntPtr NSAutoreleasePool = Get("NSAutoreleasePool");
public static readonly IntPtr NSDictionary = Get("NSDictionary");
public static readonly IntPtr NSNumber = Get("NSNumber");
public static readonly IntPtr NSUserDefaults = Get("NSUserDefaults");
[DllImport (Cocoa.LibObjC)] [DllImport (Cocoa.LibObjC)]
extern static IntPtr class_getName(IntPtr handle); extern static IntPtr class_getName(IntPtr handle);

View file

@ -57,9 +57,15 @@ namespace OpenTK.Platform.MacOS
[DllImport(LibObjC, EntryPoint="objc_msgSend")] [DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2, IntPtr intPtr3); public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2, IntPtr intPtr3);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr intPtr1, IntPtr intPtr2, IntPtr intPtr3, IntPtr intPtr4, IntPtr intPtr5);
[DllImport(LibObjC, EntryPoint="objc_msgSend")] [DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr p1, PointF p2); public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, IntPtr p1, PointF p2);
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, bool p1);
[DllImport(LibObjC, EntryPoint="objc_msgSend")] [DllImport(LibObjC, EntryPoint="objc_msgSend")]
public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, SizeF p1); public extern static IntPtr SendIntPtr(IntPtr receiver, IntPtr selector, SizeF p1);

View file

@ -44,7 +44,7 @@ namespace OpenTK.Platform.MacOS
internal static void Initialize() internal static void Initialize()
{ {
// Create the NSAutoreleasePool // Create the NSAutoreleasePool
AutoreleasePool = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.Get("NSAutoreleasePool"), Selector.Alloc), Selector.Init); AutoreleasePool = Cocoa.SendIntPtr(Cocoa.SendIntPtr(Class.NSAutoreleasePool, Selector.Alloc), Selector.Init);
// Register a Quit method to be called on cmd-q // Register a Quit method to be called on cmd-q
IntPtr nsapp = Class.Get("NSApplication"); IntPtr nsapp = Class.Get("NSApplication");
@ -80,6 +80,23 @@ namespace OpenTK.Platform.MacOS
// Tell cocoa we're ready to run the application (usually called by [NSApp run]). // Tell cocoa we're ready to run the application (usually called by [NSApp run]).
Cocoa.SendVoid(Handle, Selector.Get("finishLaunching")); Cocoa.SendVoid(Handle, Selector.Get("finishLaunching"));
// Disable momentum scrolling and long-press key pop-ups
IntPtr settings = Cocoa.SendIntPtr(Class.NSDictionary, Selector.Alloc);
IntPtr momentum_scrolling = Cocoa.SendIntPtr(Class.NSNumber, Selector.Get("numberWithBool:"), false);
IntPtr press_and_hold = Cocoa.SendIntPtr(Class.NSNumber, Selector.Get("numberWithBool:"), false);
// Initialize and register the settings dictionary
settings =
Cocoa.SendIntPtr(settings, Selector.Get("initWithObjectsAndKeys:"),
momentum_scrolling, Cocoa.ToNSString("AppleMomentumScrollSupported"),
press_and_hold, Cocoa.ToNSString("ApplePressAndHoldEnabled"),
IntPtr.Zero);
Cocoa.SendVoid(
Cocoa.SendIntPtr(Class.NSUserDefaults, Selector.Get("standardUserDefaults")),
Selector.Get("registerDefaults:"),
settings);
Cocoa.SendVoid(settings, Selector.Release);
} }
internal static event EventHandler<CancelEventArgs> Quit = delegate { }; internal static event EventHandler<CancelEventArgs> Quit = delegate { };

View file

@ -1,4 +1,4 @@
#region License #region License
// //
// CocoaNativeWindow.cs // CocoaNativeWindow.cs
// //
@ -38,30 +38,14 @@ using OpenTK.Input;
namespace OpenTK.Platform.MacOS namespace OpenTK.Platform.MacOS
{ {
class CocoaNativeWindow : INativeWindow class CocoaNativeWindow : NativeWindowBase
{ {
static int UniqueId; static int UniqueId;
public event EventHandler<EventArgs> Move = delegate { };
public event EventHandler<EventArgs> Resize = delegate { };
public event EventHandler<System.ComponentModel.CancelEventArgs> Closing = delegate { };
public event EventHandler<EventArgs> Closed = delegate { };
public event EventHandler<EventArgs> Disposed = delegate { };
public event EventHandler<EventArgs> IconChanged = delegate { };
public event EventHandler<EventArgs> TitleChanged = delegate { };
public event EventHandler<EventArgs> VisibleChanged = delegate { };
public event EventHandler<EventArgs> FocusedChanged = delegate { };
public event EventHandler<EventArgs> WindowBorderChanged = delegate { };
public event EventHandler<EventArgs> WindowStateChanged = delegate { };
public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyDown = delegate { };
public event EventHandler<KeyPressEventArgs> KeyPress = delegate { };
public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyUp = delegate { };
public event EventHandler<EventArgs> MouseLeave = delegate { };
public event EventHandler<EventArgs> MouseEnter = delegate { };
static readonly IntPtr selNextEventMatchingMask = Selector.Get("nextEventMatchingMask:untilDate:inMode:dequeue:"); static readonly IntPtr selNextEventMatchingMask = Selector.Get("nextEventMatchingMask:untilDate:inMode:dequeue:");
static readonly IntPtr selSendEvent = Selector.Get("sendEvent:"); static readonly IntPtr selSendEvent = Selector.Get("sendEvent:");
//static readonly IntPtr selUpdateWindows = Selector.Get("updateWindows"); //static readonly IntPtr selUpdateWindows = Selector.Get("updateWindows");
static readonly IntPtr selContentView = Selector.Get("contentView");
static readonly IntPtr selConvertRectFromScreen = Selector.Get("convertRectFromScreen:"); static readonly IntPtr selConvertRectFromScreen = Selector.Get("convertRectFromScreen:");
static readonly IntPtr selConvertRectToScreen = Selector.Get("convertRectToScreen:"); static readonly IntPtr selConvertRectToScreen = Selector.Get("convertRectToScreen:");
static readonly IntPtr selPerformClose = Selector.Get("performClose:"); static readonly IntPtr selPerformClose = Selector.Get("performClose:");
@ -94,7 +78,10 @@ namespace OpenTK.Platform.MacOS
static readonly IntPtr selLocationInWindowOwner = Selector.Get("locationInWindow"); static readonly IntPtr selLocationInWindowOwner = Selector.Get("locationInWindow");
static readonly IntPtr selHide = Selector.Get("hide"); static readonly IntPtr selHide = Selector.Get("hide");
static readonly IntPtr selUnhide = Selector.Get("unhide"); static readonly IntPtr selUnhide = Selector.Get("unhide");
static readonly IntPtr selScrollingDeltaX = Selector.Get("scrollingDeltaX");
static readonly IntPtr selScrollingDeltaY = Selector.Get("scrollingDeltaY"); static readonly IntPtr selScrollingDeltaY = Selector.Get("scrollingDeltaY");
static readonly IntPtr selDeltaX = Selector.Get("deltaX");
static readonly IntPtr selDeltaY = Selector.Get("deltaY");
static readonly IntPtr selButtonNumber = Selector.Get("buttonNumber"); static readonly IntPtr selButtonNumber = Selector.Get("buttonNumber");
static readonly IntPtr selSetStyleMask = Selector.Get("setStyleMask:"); static readonly IntPtr selSetStyleMask = Selector.Get("setStyleMask:");
static readonly IntPtr selStyleMask = Selector.Get("styleMask"); static readonly IntPtr selStyleMask = Selector.Get("styleMask");
@ -145,13 +132,10 @@ namespace OpenTK.Platform.MacOS
private bool exists; private bool exists;
private bool cursorVisible = true; private bool cursorVisible = true;
private System.Drawing.Icon icon; private System.Drawing.Icon icon;
private LegacyInputDriver inputDriver = new LegacyInputDriver();
private WindowBorder windowBorder = WindowBorder.Resizable; private WindowBorder windowBorder = WindowBorder.Resizable;
private Nullable<WindowBorder> deferredWindowBorder; private Nullable<WindowBorder> deferredWindowBorder;
private Nullable<WindowBorder> previousWindowBorder; private Nullable<WindowBorder> previousWindowBorder;
private WindowState windowState = WindowState.Normal; private WindowState windowState = WindowState.Normal;
private OpenTK.Input.KeyboardKeyEventArgs keyArgs = new OpenTK.Input.KeyboardKeyEventArgs();
private KeyPressEventArgs keyPressArgs = new KeyPressEventArgs((char)0);
private string title; private string title;
private RectangleF previousBounds; private RectangleF previousBounds;
private int normalLevel; private int normalLevel;
@ -160,7 +144,7 @@ namespace OpenTK.Platform.MacOS
private bool cursorInsideWindow = true; private bool cursorInsideWindow = true;
private MouseCursor selectedCursor = MouseCursor.Default; // user-selected cursor private MouseCursor selectedCursor = MouseCursor.Default; // user-selected cursor
private const float scrollFactor = 120.0f; private const float scrollFactor = 10.0f;
private const bool exclusiveFullscreen = false; private const bool exclusiveFullscreen = false;
public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) public CocoaNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
@ -188,7 +172,17 @@ namespace OpenTK.Platform.MacOS
Class.RegisterClass(viewClass); Class.RegisterClass(viewClass);
// Create window instance // Create window instance
var contentRect = new System.Drawing.RectangleF(x, y, width, height); // Note: The coordinate system of Cocoa places (0,0) at the bottom left.
// We need to get the height of the main screen and flip that in order
// to place the window at the correct position.
// Note: NSWindows are laid out relative to the main screen.
var screenRect =
Cocoa.SendRect(
Cocoa.SendIntPtr(
Cocoa.SendIntPtr(Class.Get("NSScreen"), Selector.Get("screens")),
Selector.Get("objectAtIndex:"), 0),
Selector.Get("frame"));
var contentRect = new System.Drawing.RectangleF(x, screenRect.Height - height - y, width, height);
var style = GetStyleMask(windowBorder); var style = GetStyleMask(windowBorder);
var bufferingType = NSBackingStore.Buffered; var bufferingType = NSBackingStore.Buffered;
@ -259,7 +253,7 @@ namespace OpenTK.Platform.MacOS
GraphicsContext.CurrentContext.Update(windowInfo); GraphicsContext.CurrentContext.Update(windowInfo);
if (suppressResize == 0) if (suppressResize == 0)
Resize(this, EventArgs.Empty); OnResize(EventArgs.Empty);
} }
private void ApplicationQuit(object sender, CancelEventArgs e) private void ApplicationQuit(object sender, CancelEventArgs e)
@ -272,17 +266,17 @@ namespace OpenTK.Platform.MacOS
{ {
// Problem: Called only when you stop moving for a brief moment, // Problem: Called only when you stop moving for a brief moment,
// not each frame as it is on PC. // not each frame as it is on PC.
Move(this, EventArgs.Empty); OnMove(EventArgs.Empty);
} }
private void WindowDidBecomeKey(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidBecomeKey(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
FocusedChanged(this, EventArgs.Empty); OnFocusedChanged(EventArgs.Empty);
} }
private void WindowDidResignKey(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidResignKey(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
FocusedChanged(this, EventArgs.Empty); OnFocusedChanged(EventArgs.Empty);
} }
private void WindowWillMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowWillMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification)
@ -296,14 +290,14 @@ namespace OpenTK.Platform.MacOS
private void WindowDidMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidMiniaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
windowState = WindowState.Minimized; windowState = WindowState.Minimized;
WindowStateChanged(this, EventArgs.Empty); OnWindowStateChanged(EventArgs.Empty);
OnResize(false); // Don't set tracking area when we minimize OnResize(false); // Don't set tracking area when we minimize
} }
private void WindowDidDeminiaturize(IntPtr self, IntPtr cmd, IntPtr notification) private void WindowDidDeminiaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{ {
windowState = WindowState.Normal; windowState = WindowState.Normal;
WindowStateChanged(this, EventArgs.Empty); OnWindowStateChanged(EventArgs.Empty);
OnResize(true); OnResize(true);
} }
@ -321,7 +315,7 @@ namespace OpenTK.Platform.MacOS
InternalBounds = toFrame; InternalBounds = toFrame;
windowState = WindowState.Maximized; windowState = WindowState.Maximized;
WindowStateChanged(this, EventArgs.Empty); OnWindowStateChanged(EventArgs.Empty);
} }
return false; return false;
} }
@ -329,11 +323,11 @@ namespace OpenTK.Platform.MacOS
private bool WindowShouldClose(IntPtr self, IntPtr cmd, IntPtr sender) private bool WindowShouldClose(IntPtr self, IntPtr cmd, IntPtr sender)
{ {
var cancelArgs = new CancelEventArgs(); var cancelArgs = new CancelEventArgs();
Closing(this, cancelArgs); OnClosing(cancelArgs);
if (!cancelArgs.Cancel) if (!cancelArgs.Cancel)
{ {
Closed(this, EventArgs.Empty); OnClosed(EventArgs.Empty);
return true; return true;
} }
@ -377,7 +371,7 @@ namespace OpenTK.Platform.MacOS
Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea); Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea);
} }
public void Close() public override void Close()
{ {
shouldClose = true; shouldClose = true;
} }
@ -391,13 +385,6 @@ namespace OpenTK.Platform.MacOS
return modifiers; return modifiers;
} }
private void GetKey(ushort keyCode, NSEventModifierMask modifierFlags, OpenTK.Input.KeyboardKeyEventArgs args)
{
args.Key = MacOSKeyMap.GetKey((Carbon.MacOSKeyCode)keyCode);
args.Modifiers = GetModifiers(modifierFlags);
args.ScanCode = (uint)keyCode;
}
private MouseButton GetMouseButton(int cocoaButtonIndex) private MouseButton GetMouseButton(int cocoaButtonIndex)
{ {
if (cocoaButtonIndex == 0) return MouseButton.Left; if (cocoaButtonIndex == 0) return MouseButton.Left;
@ -409,8 +396,10 @@ namespace OpenTK.Platform.MacOS
return (MouseButton)cocoaButtonIndex; return (MouseButton)cocoaButtonIndex;
} }
public void ProcessEvents() public override void ProcessEvents()
{ {
base.ProcessEvents();
while (true) while (true)
{ {
var e = Cocoa.SendIntPtr(NSApplication.Handle, selNextEventMatchingMask, uint.MaxValue, IntPtr.Zero, NSDefaultRunLoopMode, true); var e = Cocoa.SendIntPtr(NSApplication.Handle, selNextEventMatchingMask, uint.MaxValue, IntPtr.Zero, NSDefaultRunLoopMode, true);
@ -423,16 +412,11 @@ namespace OpenTK.Platform.MacOS
{ {
case NSEventType.KeyDown: case NSEventType.KeyDown:
{ {
var keyCode = Cocoa.SendUshort(e, selKeyCode); MacOSKeyCode keyCode = (MacOSKeyCode)Cocoa.SendUshort(e, selKeyCode);
var modifierFlags = (NSEventModifierMask)Cocoa.SendUint(e, selModifierFlags);
var isARepeat = Cocoa.SendBool(e, selIsARepeat); var isARepeat = Cocoa.SendBool(e, selIsARepeat);
GetKey(keyCode, modifierFlags, keyArgs); Key key = MacOSKeyMap.GetKey(keyCode);
InputDriver.Keyboard[0].SetKey(keyArgs.Key, keyArgs.ScanCode, true);
if (!isARepeat || InputDriver.Keyboard[0].KeyRepeat) OnKeyDown(key, isARepeat);
{
KeyDown(this, keyArgs);
}
var s = Cocoa.FromNSString(Cocoa.SendIntPtr(e, selCharactersIgnoringModifiers)); var s = Cocoa.FromNSString(Cocoa.SendIntPtr(e, selCharactersIgnoringModifiers));
foreach (var c in s) foreach (var c in s)
@ -440,10 +424,9 @@ namespace OpenTK.Platform.MacOS
int intVal = (int)c; int intVal = (int)c;
if (!Char.IsControl(c) && (intVal < 63232 || intVal > 63235)) if (!Char.IsControl(c) && (intVal < 63232 || intVal > 63235))
{ {
// For some reason, arrow keys (mapped 63232-63235) are seen as non-control characters, so get rid of those. // For some reason, arrow keys (mapped 63232-63235)
// are seen as non-control characters, so get rid of those.
keyPressArgs.KeyChar = c; OnKeyPress(c);
KeyPress(this, keyPressArgs);
} }
} }
} }
@ -451,13 +434,16 @@ namespace OpenTK.Platform.MacOS
case NSEventType.KeyUp: case NSEventType.KeyUp:
{ {
var keyCode = Cocoa.SendUshort(e, selKeyCode); MacOSKeyCode keyCode = (MacOSKeyCode)Cocoa.SendUshort(e, selKeyCode);
Key key = MacOSKeyMap.GetKey(keyCode);
OnKeyUp(key);
}
break;
case NSEventType.FlagsChanged:
{
var modifierFlags = (NSEventModifierMask)Cocoa.SendUint(e, selModifierFlags); var modifierFlags = (NSEventModifierMask)Cocoa.SendUint(e, selModifierFlags);
UpdateModifierFlags(GetModifiers(modifierFlags));
GetKey(keyCode, modifierFlags, keyArgs);
InputDriver.Keyboard[0].SetKey(keyArgs.Key, keyArgs.ScanCode, false);
KeyUp(this, keyArgs);
} }
break; break;
@ -472,8 +458,7 @@ namespace OpenTK.Platform.MacOS
//SetCursor(selectedCursor); //SetCursor(selectedCursor);
} }
cursorInsideWindow = true; OnMouseEnter(EventArgs.Empty);
MouseEnter(this, EventArgs.Empty);
} }
} }
break; break;
@ -486,11 +471,10 @@ namespace OpenTK.Platform.MacOS
{ {
if (selectedCursor != MouseCursor.Default) if (selectedCursor != MouseCursor.Default)
{ {
SetCursor(MouseCursor.Default); //SetCursor(MouseCursor.Default);
} }
cursorInsideWindow = false; OnMouseLeave(EventArgs.Empty);
MouseLeave(this, EventArgs.Empty);
} }
} }
break; break;
@ -500,6 +484,10 @@ namespace OpenTK.Platform.MacOS
case NSEventType.OtherMouseDragged: case NSEventType.OtherMouseDragged:
case NSEventType.MouseMoved: case NSEventType.MouseMoved:
{ {
Point p = new Point(MouseState.X, MouseState.Y);
if (CursorVisible)
{
// Use absolute coordinates
var pf = Cocoa.SendPoint(e, selLocationInWindowOwner); var pf = Cocoa.SendPoint(e, selLocationInWindowOwner);
// Convert from points to pixel coordinates // Convert from points to pixel coordinates
@ -507,11 +495,27 @@ namespace OpenTK.Platform.MacOS
new RectangleF(pf.X, pf.Y, 0, 0)); new RectangleF(pf.X, pf.Y, 0, 0));
// See CocoaDrawingGuide under "Converting from Window to View Coordinates" // See CocoaDrawingGuide under "Converting from Window to View Coordinates"
var p = new Point( p = new Point(
MathHelper.Clamp((int)Math.Round(rf.X), 0, Width), MathHelper.Clamp((int)Math.Round(rf.X), 0, Width),
MathHelper.Clamp((int)Math.Round(Height - rf.Y), 0, Height)); MathHelper.Clamp((int)Math.Round(Height - rf.Y), 0, Height));
}
else
{
// Mouse has been disassociated,
// use relative coordinates
var dx = Cocoa.SendFloat(e, selDeltaX);
var dy = Cocoa.SendFloat(e, selDeltaY);
InputDriver.Mouse[0].Position = p; p = new Point(
MathHelper.Clamp((int)Math.Round(p.X + dx), 0, Width),
MathHelper.Clamp((int)Math.Round(p.Y + dy), 0, Height));
}
// Only raise events when the mouse has actually moved
if (MouseState.X != p.X || MouseState.Y != p.Y)
{
OnMouseMove(p.X, p.Y);
}
} }
break; break;
@ -520,15 +524,23 @@ namespace OpenTK.Platform.MacOS
case NSEventType.ScrollWheel: case NSEventType.ScrollWheel:
{ {
var scrollingDelta = Cocoa.SendFloat(e, selScrollingDeltaY); float dx, dy;
var factor = 1.0f;
if (Cocoa.SendBool(e, selHasPreciseScrollingDeltas)) if (Cocoa.SendBool(e, selHasPreciseScrollingDeltas))
{ {
factor = 1.0f / scrollFactor; // Problem: Don't know what factor to use here, but this seems to work. dx = Cocoa.SendFloat(e, selScrollingDeltaX) / scrollFactor;
dy = Cocoa.SendFloat(e, selScrollingDeltaY) / scrollFactor;
}
else
{
dx = Cocoa.SendFloat(e, selDeltaX);
dy = Cocoa.SendFloat(e, selDeltaY);
} }
InputDriver.Mouse[0].WheelPrecise += scrollingDelta * factor; // Only raise wheel events when the user has actually scrolled
if (dx != 0 || dy != 0)
{
OnMouseWheel(dx, dy);
}
} }
break; break;
@ -537,7 +549,7 @@ namespace OpenTK.Platform.MacOS
case NSEventType.OtherMouseDown: case NSEventType.OtherMouseDown:
{ {
var buttonNumber = Cocoa.SendInt(e, selButtonNumber); var buttonNumber = Cocoa.SendInt(e, selButtonNumber);
InputDriver.Mouse[0][GetMouseButton(buttonNumber)] = true; OnMouseDown(GetMouseButton(buttonNumber));
} }
break; break;
@ -546,7 +558,7 @@ namespace OpenTK.Platform.MacOS
case NSEventType.OtherMouseUp: case NSEventType.OtherMouseUp:
{ {
var buttonNumber = Cocoa.SendInt(e, selButtonNumber); var buttonNumber = Cocoa.SendInt(e, selButtonNumber);
InputDriver.Mouse[0][GetMouseButton(buttonNumber)] = false; OnMouseUp(GetMouseButton(buttonNumber));
} }
break; break;
} }
@ -575,19 +587,25 @@ namespace OpenTK.Platform.MacOS
} }
} }
public System.Drawing.Point PointToClient(System.Drawing.Point point) public override System.Drawing.Point PointToClient(System.Drawing.Point point)
{ {
var r = Cocoa.SendRect(windowInfo.Handle, selConvertRectFromScreen, new RectangleF(point.X, point.Y, 0, 0)); var r =
return new Point((int)r.X, (int)(GetContentViewFrame().Height - GetCurrentScreenFrame().Height - r.Y)); Cocoa.SendRect(windowInfo.ViewHandle, selConvertRectToBacking,
Cocoa.SendRect(windowInfo.Handle, selConvertRectFromScreen,
new RectangleF(point.X, GetCurrentScreenFrame().Height - point.Y, 0, 0)));
return new Point((int)r.X, (int)(Height - r.Y));
} }
public System.Drawing.Point PointToScreen(System.Drawing.Point point) public override System.Drawing.Point PointToScreen(System.Drawing.Point point)
{ {
var r = Cocoa.SendRect(windowInfo.Handle, selConvertRectToScreen, new RectangleF(point.X, point.Y, 0, 0)); var r =
return new Point((int)r.X, (int)(-GetContentViewFrame().Height + GetCurrentScreenFrame().Height - r.Y)); Cocoa.SendRect(windowInfo.Handle, selConvertRectToScreen,
Cocoa.SendRect(windowInfo.ViewHandle, selConvertRectFromBacking,
new RectangleF(point.X, Height - point.Y, 0, 0)));
return new Point((int)r.X, (int)(GetCurrentScreenFrame().Height - r.Y));
} }
public System.Drawing.Icon Icon public override System.Drawing.Icon Icon
{ {
get { return icon; } get { return icon; }
set set
@ -598,11 +616,11 @@ namespace OpenTK.Platform.MacOS
IntPtr nsimg = Cocoa.ToNSImage(img); IntPtr nsimg = Cocoa.ToNSImage(img);
Cocoa.SendVoid(NSApplication.Handle, selSetApplicationIconImage, nsimg); Cocoa.SendVoid(NSApplication.Handle, selSetApplicationIconImage, nsimg);
} }
IconChanged(this, EventArgs.Empty); OnIconChanged(EventArgs.Empty);
} }
} }
public string Title public override string Title
{ {
get get
{ {
@ -614,7 +632,7 @@ namespace OpenTK.Platform.MacOS
} }
} }
public bool Focused public override bool Focused
{ {
get get
{ {
@ -622,7 +640,7 @@ namespace OpenTK.Platform.MacOS
} }
} }
public bool Visible public override bool Visible
{ {
get get
{ {
@ -631,11 +649,11 @@ namespace OpenTK.Platform.MacOS
set set
{ {
Cocoa.SendVoid(windowInfo.Handle, selSetIsVisible, value); Cocoa.SendVoid(windowInfo.Handle, selSetIsVisible, value);
VisibleChanged(this, EventArgs.Empty); OnVisibleChanged(EventArgs.Empty);
} }
} }
public bool Exists public override bool Exists
{ {
get get
{ {
@ -643,7 +661,7 @@ namespace OpenTK.Platform.MacOS
} }
} }
public IWindowInfo WindowInfo public override IWindowInfo WindowInfo
{ {
get get
{ {
@ -702,7 +720,7 @@ namespace OpenTK.Platform.MacOS
previousWindowBorder = null; previousWindowBorder = null;
} }
public WindowState WindowState public override WindowState WindowState
{ {
get get
{ {
@ -735,7 +753,7 @@ namespace OpenTK.Platform.MacOS
InternalBounds = GetCurrentScreenFrame(); InternalBounds = GetCurrentScreenFrame();
windowState = value; windowState = value;
WindowStateChanged(this, EventArgs.Empty); OnWindowStateChanged(EventArgs.Empty);
} }
else if (value == WindowState.Maximized) else if (value == WindowState.Maximized)
{ {
@ -748,13 +766,13 @@ namespace OpenTK.Platform.MacOS
else if (value == WindowState.Normal) else if (value == WindowState.Normal)
{ {
windowState = value; windowState = value;
WindowStateChanged(this, EventArgs.Empty); OnWindowStateChanged(EventArgs.Empty);
Resize(this, EventArgs.Empty); OnResize(EventArgs.Empty);
} }
} }
} }
public WindowBorder WindowBorder public override WindowBorder WindowBorder
{ {
get get
{ {
@ -773,7 +791,7 @@ namespace OpenTK.Platform.MacOS
return; return;
SetWindowBorder(value); SetWindowBorder(value);
WindowBorderChanged(this, EventArgs.Empty); OnWindowBorderChanged(EventArgs.Empty);
} }
} }
@ -795,16 +813,26 @@ namespace OpenTK.Platform.MacOS
return (NSWindowStyle)0; return (NSWindowStyle)0;
} }
public System.Drawing.Rectangle Bounds public override System.Drawing.Rectangle Bounds
{ {
get get
{ {
var r = Cocoa.SendRect(windowInfo.Handle, selFrame); var r = Cocoa.SendRect(windowInfo.Handle, selFrame);
return new Rectangle((int)r.X, (int)(GetCurrentScreenFrame().Height - r.Y), (int)r.Width, (int)r.Height); return new Rectangle(
(int)r.X,
(int)(GetCurrentScreenFrame().Height - r.Y - r.Height),
(int)r.Width,
(int)r.Height);
} }
set set
{ {
Cocoa.SendVoid(windowInfo.Handle, selSetFrame, new RectangleF(value.X, GetCurrentScreenFrame().Height - value.Y, value.Width, value.Height), true); Cocoa.SendVoid(windowInfo.Handle, selSetFrame,
new RectangleF(
value.X,
GetCurrentScreenFrame().Height - value.Y - value.Height,
value.Width,
value.Height),
true);
} }
} }
@ -820,105 +848,13 @@ namespace OpenTK.Platform.MacOS
} }
} }
public System.Drawing.Point Location public override System.Drawing.Size ClientSize
{
get
{
return Bounds.Location;
}
set
{
var b = Bounds;
b.Location = value;
Bounds = b;
}
}
public System.Drawing.Size Size
{
get
{
return Bounds.Size;
}
set
{
var b = Bounds;
b.Y -= Bounds.Height;
b.Y += value.Height;
b.Size = value;
Bounds = b;
}
}
public int X
{
get
{
return Bounds.X;
}
set
{
var b = Bounds;
b.X = value;
Bounds = b;
}
}
public int Y
{
get
{
return Bounds.Y;
}
set
{
var b = Bounds;
b.Y = value;
Bounds = b;
}
}
public int Width
{
get { return ClientRectangle.Width; }
set
{
var s = ClientSize;
s.Width = value;
ClientSize = s;
}
}
public int Height
{
get { return ClientRectangle.Height; }
set
{
var s = ClientSize;
s.Height = value;
ClientSize = s;
}
}
public System.Drawing.Rectangle ClientRectangle
{ {
get get
{ {
var contentViewBounds = Cocoa.SendRect(windowInfo.ViewHandle, selBounds); var contentViewBounds = Cocoa.SendRect(windowInfo.ViewHandle, selBounds);
var bounds = Cocoa.SendRect(windowInfo.Handle, selConvertRectToBacking, contentViewBounds); var bounds = Cocoa.SendRect(windowInfo.Handle, selConvertRectToBacking, contentViewBounds);
return new Rectangle((int)bounds.X, (int)bounds.Y, (int)bounds.Width, (int)bounds.Height); return new Size((int)bounds.Width, (int)bounds.Height);
}
set
{
ClientSize = value.Size; // Just set size, to be consistent with WinGLNative.
}
}
public System.Drawing.Size ClientSize
{
get
{
return ClientRectangle.Size;
} }
set set
{ {
@ -928,15 +864,7 @@ namespace OpenTK.Platform.MacOS
} }
} }
public OpenTK.Input.IInputDriver InputDriver public override MouseCursor Cursor
{
get
{
return inputDriver;
}
}
public MouseCursor Cursor
{ {
get get
{ {
@ -1058,7 +986,7 @@ namespace OpenTK.Platform.MacOS
Cocoa.SendVoid(windowInfo.Handle, selInvalidateCursorRectsForView, windowInfo.ViewHandle); Cocoa.SendVoid(windowInfo.Handle, selInvalidateCursorRectsForView, windowInfo.ViewHandle);
} }
public bool CursorVisible public override bool CursorVisible
{ {
get { return cursorVisible; } get { return cursorVisible; }
set set
@ -1075,13 +1003,7 @@ namespace OpenTK.Platform.MacOS
} }
} }
public void Dispose() protected override void Dispose(bool disposing)
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{ {
if (disposed) if (disposed)
return; return;
@ -1105,12 +1027,12 @@ namespace OpenTK.Platform.MacOS
Cocoa.SendVoid(windowInfo.Handle, Selector.Release); Cocoa.SendVoid(windowInfo.Handle, Selector.Release);
} }
Disposed(this, EventArgs.Empty); OnDisposed(EventArgs.Empty);
} }
~CocoaNativeWindow() public static IntPtr GetView(IntPtr windowHandle)
{ {
Dispose(false); return Cocoa.SendIntPtr(windowHandle, selContentView);
} }
private RectangleF GetContentViewFrame() private RectangleF GetContentViewFrame()
@ -1135,23 +1057,25 @@ namespace OpenTK.Platform.MacOS
private void SetCursorVisible(bool visible) private void SetCursorVisible(bool visible)
{ {
Carbon.CG.AssociateMouseAndMouseCursorPosition(visible); // If the mouse is outside the window and we want to hide it,
Cocoa.SendVoid(NSCursor, visible ? selUnhide : selHide); // move it inside the window first.
// Otherwise, if we are making the cursor visible again,
// we place it in the same spot as reported in the current
// MouseState to avoid sudden jumps.
if (!visible && !Bounds.Contains(new Point(MouseState.X, MouseState.Y)))
{
Mouse.SetPosition(
(Bounds.Left + Bounds.Right) / 2,
(Bounds.Top + Bounds.Bottom) / 2);
}
else if (visible)
{
var p = PointToScreen(new Point(MouseState.X, MouseState.Y));
Mouse.SetPosition((int)p.X, (int)p.Y);
} }
private void SetCursor(MouseCursor cursor) Carbon.CG.AssociateMouseAndMouseCursorPosition(visible);
{ Cocoa.SendVoid(NSCursor, visible ? selUnhide : selHide);
if (cursor == MouseCursor.Default)
{
Cocoa.SendVoid(NSCursor, selUnhide);
}
else if (cursor == MouseCursor.Empty)
{
Cocoa.SendVoid(NSCursor, selHide);
}
else
{
}
} }
private void SetMenuVisible(bool visible) private void SetMenuVisible(bool visible)
@ -1178,7 +1102,7 @@ namespace OpenTK.Platform.MacOS
Cocoa.SendIntPtr(windowInfo.Handle, selSetTitle, Cocoa.ToNSString(title)); Cocoa.SendIntPtr(windowInfo.Handle, selSetTitle, Cocoa.ToNSString(title));
if (callEvent) if (callEvent)
{ {
TitleChanged(this, EventArgs.Empty); OnTitleChanged(EventArgs.Empty);
} }
} }

View file

@ -324,7 +324,7 @@ namespace OpenTK.Platform.MacOS
break; break;
case HIDUsageGD.Wheel: case HIDUsageGD.Wheel:
mouse.State.WheelPrecise += v_int; mouse.State.SetScrollRelative(0, v_int);
break; break;
} }
break; break;
@ -332,6 +332,15 @@ namespace OpenTK.Platform.MacOS
case HIDPage.Button: case HIDPage.Button:
mouse.State[OpenTK.Input.MouseButton.Left + usage - 1] = v_int == 1; mouse.State[OpenTK.Input.MouseButton.Left + usage - 1] = v_int == 1;
break; break;
case HIDPage.Consumer:
switch ((HIDUsageCD)usage)
{
case HIDUsageCD.ACPan:
mouse.State.SetScrollRelative(v_int, 0);
break;
}
break;
} }
} }
@ -381,7 +390,8 @@ namespace OpenTK.Platform.MacOS
{ {
Debug.Print("[Warning] Key {0} not mapped.", usage); Debug.Print("[Warning] Key {0} not mapped.", usage);
} }
keyboard.State.SetKeyState(RawKeyMap[usage], (byte)usage, v_int != 0);
keyboard.State[RawKeyMap[usage]] = v_int != 0;
break; break;
} }
} }
@ -1107,6 +1117,12 @@ namespace OpenTK.Platform.MacOS
VendorDefinedStart = 0xFF00 VendorDefinedStart = 0xFF00
} }
// Consumer electronic devices
enum HIDUsageCD
{
ACPan = 0x0238
}
// Generic desktop usage // Generic desktop usage
enum HIDUsageGD enum HIDUsageGD
{ {

View file

@ -0,0 +1,477 @@
#region License
//
// NativeWindowBase.cs
//
// Author:
// Stefanos A. <stapostol@gmail.com>
//
// Copyright (c) 2006-2014 Stefanos Apostolopoulos
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#endregion
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using OpenTK.Input;
namespace OpenTK.Platform
{
// Common base class for all INativeWindow implementations
abstract class NativeWindowBase : INativeWindow
{
readonly LegacyInputDriver LegacyInputDriver;
readonly MouseButtonEventArgs MouseDownArgs = new MouseButtonEventArgs();
readonly MouseButtonEventArgs MouseUpArgs = new MouseButtonEventArgs();
readonly MouseMoveEventArgs MouseMoveArgs = new MouseMoveEventArgs();
readonly MouseWheelEventArgs MouseWheelArgs = new MouseWheelEventArgs();
readonly KeyboardKeyEventArgs KeyDownArgs = new KeyboardKeyEventArgs();
readonly KeyboardKeyEventArgs KeyUpArgs = new KeyboardKeyEventArgs();
readonly KeyPressEventArgs KeyPressArgs = new KeyPressEventArgs((char)0);
// In order to simplify mouse event implementation,
// we can store the current mouse state here.
protected MouseState MouseState = new MouseState();
protected KeyboardState KeyboardState = new KeyboardState();
MouseState PreviousMouseState = new MouseState();
internal NativeWindowBase()
{
LegacyInputDriver = new LegacyInputDriver(this);
MouseState.SetIsConnected(true);
KeyboardState.SetIsConnected(true);
PreviousMouseState.SetIsConnected(true);
}
#region Protected Members
protected void OnMove(EventArgs e)
{
Move(this, e);
}
protected void OnResize(EventArgs e)
{
Resize(this, e);
}
protected void OnClosing(CancelEventArgs e)
{
Closing(this, e);
}
protected void OnClosed(EventArgs e)
{
Closed(this, e);
}
protected void OnDisposed(EventArgs e)
{
Disposed(this, e);
}
protected void OnIconChanged(EventArgs e)
{
IconChanged(this, e);
}
protected void OnTitleChanged(EventArgs e)
{
TitleChanged(this, e);
}
protected void OnVisibleChanged(EventArgs e)
{
VisibleChanged(this, e);
}
protected void OnFocusedChanged(EventArgs e)
{
FocusedChanged(this, e);
}
protected void OnWindowBorderChanged(EventArgs e)
{
WindowBorderChanged(this, e);
}
protected void OnWindowStateChanged(EventArgs e)
{
WindowStateChanged(this, e);
}
protected void OnKeyDown(Key key, bool repeat)
{
KeyboardState.SetKeyState(key, true);
var e = KeyDownArgs;
e.Keyboard = KeyboardState;
e.Key = key;
e.IsRepeat = repeat;
KeyDown(this, e);
}
protected void OnKeyPress(char c)
{
var e = KeyPressArgs;
e.KeyChar = c;
KeyPress(this, e);
}
protected void OnKeyUp(Key key)
{
KeyboardState.SetKeyState(key, false);
var e = KeyUpArgs;
e.Keyboard = KeyboardState;
e.Key = key;
e.IsRepeat = false;
KeyUp(this, e);
}
/// \internal
/// <summary>
/// Call this method to simulate KeyDown/KeyUp events
/// on platforms that do not generate key events for
/// modifier flags (e.g. Mac/Cocoa).
/// Note: this method does not distinguish between the
/// left and right variants of modifier keys.
/// </summary>
/// <param name="mods">Mods.</param>
protected void UpdateModifierFlags(KeyModifiers mods)
{
bool alt = (mods & KeyModifiers.Alt) != 0;
bool control = (mods & KeyModifiers.Control) != 0;
bool shift = (mods & KeyModifiers.Shift) != 0;
if (alt)
{
OnKeyDown(Key.AltLeft, KeyboardState[Key.AltLeft]);
OnKeyDown(Key.AltRight, KeyboardState[Key.AltLeft]);
}
else
{
if (KeyboardState[Key.AltLeft])
{
OnKeyUp(Key.AltLeft);
}
if (KeyboardState[Key.AltRight])
{
OnKeyUp(Key.AltRight);
}
}
if (control)
{
OnKeyDown(Key.ControlLeft, KeyboardState[Key.AltLeft]);
OnKeyDown(Key.ControlRight, KeyboardState[Key.AltLeft]);
}
else
{
if (KeyboardState[Key.ControlLeft])
{
OnKeyUp(Key.ControlLeft);
}
if (KeyboardState[Key.ControlRight])
{
OnKeyUp(Key.ControlRight);
}
}
if (shift)
{
OnKeyDown(Key.ShiftLeft, KeyboardState[Key.AltLeft]);
OnKeyDown(Key.ShiftRight, KeyboardState[Key.AltLeft]);
}
else
{
if (KeyboardState[Key.ShiftLeft])
{
OnKeyUp(Key.ShiftLeft);
}
if (KeyboardState[Key.ShiftRight])
{
OnKeyUp(Key.ShiftRight);
}
}
}
protected void OnMouseLeave(EventArgs e)
{
MouseLeave(this, e);
}
protected void OnMouseEnter(EventArgs e)
{
MouseEnter(this, e);
}
protected void OnMouseDown(MouseButton button)
{
MouseState[button] = true;
var e = MouseDownArgs;
e.Mouse = MouseState;
MouseDown(this, e);
}
protected void OnMouseUp(MouseButton button)
{
MouseState[button] = false;
var e = MouseUpArgs;
e.Mouse = MouseState;
MouseUp(this, e);
}
protected void OnMouseMove(int x, int y)
{
MouseState.X = x;
MouseState.Y = y;
var e = MouseMoveArgs;
e.Mouse = MouseState;
e.XDelta = MouseState.X - PreviousMouseState.X;
e.YDelta = MouseState.Y - PreviousMouseState.Y;
if (e.XDelta == 0 && e.YDelta == 0)
{
Debug.WriteLine("OnMouseMove called without moving the mouse");
return;
}
PreviousMouseState = MouseState;
MouseMove(this, e);
}
protected void OnMouseWheel(float dx, float dy)
{
MouseState.SetScrollRelative(dx, dy);
var e = MouseWheelArgs;
e.Mouse = MouseState;
e.DeltaPrecise = MouseState.Scroll.Y - PreviousMouseState.Scroll.Y;
if (dx == 0 && dy == 0)
{
Debug.WriteLine("OnMouseWheel called without moving the mouse wheel.");
return;
}
PreviousMouseState = MouseState;
MouseWheel(this, e);
}
#endregion
#region INativeWindow Members
public event EventHandler<EventArgs> Move = delegate { };
public event EventHandler<EventArgs> Resize = delegate { };
public event EventHandler<System.ComponentModel.CancelEventArgs> Closing = delegate { };
public event EventHandler<EventArgs> Closed = delegate { };
public event EventHandler<EventArgs> Disposed = delegate { };
public event EventHandler<EventArgs> IconChanged = delegate { };
public event EventHandler<EventArgs> TitleChanged = delegate { };
public event EventHandler<EventArgs> VisibleChanged = delegate { };
public event EventHandler<EventArgs> FocusedChanged = delegate { };
public event EventHandler<EventArgs> WindowBorderChanged = delegate { };
public event EventHandler<EventArgs> WindowStateChanged = delegate { };
public event EventHandler<KeyboardKeyEventArgs> KeyDown = delegate { };
public event EventHandler<KeyPressEventArgs> KeyPress = delegate { };
public event EventHandler<KeyboardKeyEventArgs> KeyUp = delegate { };
public event EventHandler<EventArgs> MouseLeave = delegate { };
public event EventHandler<EventArgs> MouseEnter = delegate { };
public event EventHandler<MouseButtonEventArgs> MouseDown = delegate { };
public event EventHandler<MouseButtonEventArgs> MouseUp = delegate { };
public event EventHandler<MouseMoveEventArgs> MouseMove = delegate { };
public event EventHandler<MouseWheelEventArgs> MouseWheel = delegate { };
public abstract void Close();
public virtual void ProcessEvents()
{
if (!Focused)
{
// Clear keyboard state, otherwise KeyUp
// events may be missed resulting in stuck
// keys.
for (Key key = 0; key < Key.LastKey; key++)
{
if (KeyboardState[key])
{
OnKeyUp(key);
}
}
}
}
public abstract Point PointToClient(Point point);
public abstract Point PointToScreen(Point point);
public abstract Icon Icon { get; set; }
public abstract string Title { get; set; }
public abstract bool Focused { get; }
public abstract bool Visible { get; set; }
public abstract bool Exists { get; }
public abstract IWindowInfo WindowInfo { get; }
public abstract WindowState WindowState { get; set; }
public abstract WindowBorder WindowBorder { get; set; }
public abstract Rectangle Bounds { get; set; }
public virtual Point Location
{
get
{
return Bounds.Location;
}
set
{
Bounds = new Rectangle(value, Bounds.Size);
}
}
public virtual Size Size
{
get
{
return Bounds.Size;
}
set
{
Bounds = new Rectangle(Bounds.Location, value);
}
}
public int X
{
get
{
return Bounds.X;
}
set
{
Rectangle old = Bounds;
Bounds = new Rectangle(value, old.Y, old.Width, old.Height);
}
}
public int Y
{
get
{
return Bounds.Y;
}
set
{
Rectangle old = Bounds;
Bounds = new Rectangle(old.X, value, old.Width, old.Height);
}
}
public int Width
{
get
{
return ClientSize.Width;
}
set
{
Rectangle old = ClientRectangle;
ClientRectangle = new Rectangle(old.X, old.Y, value, old.Height);
}
}
public int Height
{
get
{
return ClientSize.Height;
}
set
{
Rectangle old = ClientRectangle;
Bounds = new Rectangle(old.X, old.Y, old.Width, value);
}
}
public Rectangle ClientRectangle
{
get
{
return new Rectangle(Point.Empty, ClientSize);
}
set
{
ClientSize = value.Size;
}
}
public abstract Size ClientSize { get; set; }
public virtual IInputDriver InputDriver
{
get
{
return LegacyInputDriver;
}
}
public abstract bool CursorVisible { get; set; }
public abstract MouseCursor Cursor { get; set; }
#endregion
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected abstract void Dispose(bool disposing);
~NativeWindowBase()
{
Debug.Print("NativeWindowBase leaked, did you forget to call Dispose()?");
Dispose(false);
}
#endregion
}
}

View file

@ -1572,8 +1572,8 @@ namespace OpenTK.Platform.SDL2
public UInt32 Which; public UInt32 Which;
public Button Button; public Button Button;
public State State; public State State;
public byte Clicks;
byte padding1; byte padding1;
byte padding2;
public Int32 X; public Int32 X;
public Int32 Y; public Int32 Y;
} }
@ -1584,10 +1584,7 @@ namespace OpenTK.Platform.SDL2
public uint Timestamp; public uint Timestamp;
public uint WindowID; public uint WindowID;
public uint Which; public uint Which;
public State State; public ButtonFlags State;
byte padding1;
byte padding2;
byte padding3;
public Int32 X; public Int32 X;
public Int32 Y; public Int32 Y;
public Int32 Xrel; public Int32 Xrel;
@ -1617,10 +1614,6 @@ namespace OpenTK.Platform.SDL2
} }
public const uint TouchMouseID = 0xffffffff; public const uint TouchMouseID = 0xffffffff;
public static class GL
{
}
} }
struct Rect struct Rect

View file

@ -57,7 +57,7 @@ namespace OpenTK.Platform.SDL2
public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device) public override INativeWindow CreateNativeWindow(int x, int y, int width, int height, string title, GraphicsMode mode, GameWindowFlags options, DisplayDevice device)
{ {
return new Sdl2NativeWindow(x, y, width, height, title, options, device, InputDriver); return new Sdl2NativeWindow(x, y, width, height, title, options, device);
} }
public override IDisplayDeviceDriver CreateDisplayDeviceDriver() public override IDisplayDeviceDriver CreateDisplayDeviceDriver()

View file

@ -34,7 +34,7 @@ using OpenTK.Input;
namespace OpenTK.Platform.SDL2 namespace OpenTK.Platform.SDL2
{ {
class Sdl2InputDriver : IInputDriver2, IInputDriver class Sdl2InputDriver : IInputDriver2
{ {
readonly static Dictionary<IntPtr, Sdl2InputDriver> DriverHandles = readonly static Dictionary<IntPtr, Sdl2InputDriver> DriverHandles =
new Dictionary<IntPtr, Sdl2InputDriver>(); new Dictionary<IntPtr, Sdl2InputDriver>();
@ -154,51 +154,6 @@ namespace OpenTK.Platform.SDL2
#endregion #endregion
#region IInputDriver Members
public void Poll()
{
joystick_driver.Poll();
}
#endregion
#region IJoystickDriver Members
public IList<JoystickDevice> Joysticks
{
get
{
return joystick_driver.Joysticks;
}
}
#endregion
#region IMouseDriver Members
public IList<MouseDevice> Mouse
{
get
{
return mouse_driver.Mouse;
}
}
#endregion
#region IKeyboardDriver Members
public IList<KeyboardDevice> Keyboard
{
get
{
return keyboard_driver.Keyboard;
}
}
#endregion
#region IInputDriver2 Members #region IInputDriver2 Members
public IMouseDriver2 MouseDriver public IMouseDriver2 MouseDriver

View file

@ -298,6 +298,15 @@ namespace OpenTK.Platform.SDL2
return Key.Unknown; return Key.Unknown;
} }
} }
public static KeyModifiers GetModifiers(Keymod mod)
{
KeyModifiers result = 0;
result |= (mod & Keymod.ALT) != 0 ? KeyModifiers.Alt : 0;
result |= (mod & Keymod.CTRL) != 0 ? KeyModifiers.Control : 0;
result |= (mod & Keymod.SHIFT) != 0 ? KeyModifiers.Shift : 0;
return result;
}
} }
} }

View file

@ -31,7 +31,7 @@ using OpenTK.Input;
namespace OpenTK.Platform.SDL2 namespace OpenTK.Platform.SDL2
{ {
class Sdl2Keyboard : IKeyboardDriver2, IKeyboardDriver class Sdl2Keyboard : IKeyboardDriver2
{ {
KeyboardState state; KeyboardState state;
@ -42,13 +42,6 @@ namespace OpenTK.Platform.SDL2
public Sdl2Keyboard() public Sdl2Keyboard()
{ {
state.IsConnected = true; state.IsConnected = true;
keyboards.Add(new KeyboardDevice());
keyboards[0].Description = "Standard keyboard";
keyboards[0].NumberOfFunctionKeys = 12;
keyboards[0].NumberOfKeys = 101;
keyboards[0].NumberOfLeds = 3;
keyboards_readonly = keyboards.AsReadOnly();
} }
#region Private Members #region Private Members
@ -65,16 +58,16 @@ namespace OpenTK.Platform.SDL2
{ {
Keymod mod = SDL.GetModState(); Keymod mod = SDL.GetModState();
state.SetKeyState(Key.LAlt, (byte)Scancode.LALT, (mod & Keymod.LALT) != 0); state[Key.LAlt] = (mod & Keymod.LALT) != 0;
state.SetKeyState(Key.RAlt, (byte)Scancode.RALT, (mod & Keymod.RALT) != 0); state[Key.RAlt] = (mod & Keymod.RALT) != 0;
state.SetKeyState(Key.LControl, (byte)Scancode.LCTRL, (mod & Keymod.LCTRL) != 0); state[Key.LControl] = (mod & Keymod.LCTRL) != 0;
state.SetKeyState(Key.RControl, (byte)Scancode.RCTRL, (mod & Keymod.CTRL) != 0); state[Key.RControl] = (mod & Keymod.RCTRL) != 0;
state.SetKeyState(Key.LShift, (byte)Scancode.LSHIFT, (mod & Keymod.LSHIFT) != 0); state[Key.LShift] = (mod & Keymod.LSHIFT) != 0;
state.SetKeyState(Key.RShift, (byte)Scancode.RSHIFT, (mod & Keymod.RSHIFT) != 0); state[Key.RShift] = (mod & Keymod.RSHIFT) != 0;
state.SetKeyState(Key.Menu, (byte)Scancode.APPLICATION, (mod & Keymod.GUI) != 0); state[Key.Menu] = (mod & Keymod.GUI) != 0;
state.SetKeyState(Key.CapsLock, (byte)Scancode.CAPSLOCK, (mod & Keymod.CAPS) != 0); state[Key.CapsLock] = (mod & Keymod.CAPS) != 0;
state.SetKeyState(Key.NumLock, (byte)Scancode.NUMLOCKCLEAR, (mod & Keymod.NUM) != 0); state[Key.NumLock] = (mod & Keymod.NUM) != 0;
//state.SetKeyState(Key., (byte)Scancode.MODE, (mod & Keymod.MODE) != 0); //state[Key.] = (mod & Keymod.MODE) != 0;
} }
#endregion #endregion
@ -86,22 +79,11 @@ namespace OpenTK.Platform.SDL2
bool pressed = e.State != 0; bool pressed = e.State != 0;
var scancode = e.Keysym.Scancode; var scancode = e.Keysym.Scancode;
Key key = Sdl2KeyMap.GetKey(scancode); Key key = Sdl2KeyMap.GetKey(scancode);
KeyModifiers mods = Sdl2KeyMap.GetModifiers(e.Keysym.Mod);
if (key != Key.Unknown) if (key != Key.Unknown)
{ {
state.SetKeyState(key, (byte)scancode, pressed); state[key] = pressed;
keyboards[0].SetKey(key, (byte)scancode, pressed);
}
}
#endregion
#region IKeyboardDriver Members
public IList<KeyboardDevice> Keyboard
{
get
{
return keyboards_readonly;
} }
} }

View file

@ -33,28 +33,18 @@ using OpenTK.Input;
namespace OpenTK.Platform.SDL2 namespace OpenTK.Platform.SDL2
{ {
class Sdl2Mouse : IMouseDriver2, IMouseDriver class Sdl2Mouse : IMouseDriver2
{ {
MouseState state; MouseState state;
readonly List<MouseDevice> mice =
new List<MouseDevice>();
readonly IList<MouseDevice> mice_readonly;
public Sdl2Mouse() public Sdl2Mouse()
{ {
state.IsConnected = true; state.IsConnected = true;
mice.Add(new MouseDevice());
mice[0].Description = "Standard mouse";
mice[0].NumberOfButtons = 3;
mice[0].NumberOfWheels = 1;
mice_readonly = mice.AsReadOnly();
} }
#region Private Members #region Private Members
MouseButton TranslateButton(Button button) static internal MouseButton TranslateButton(Button button)
{ {
switch (button) switch (button)
{ {
@ -97,34 +87,19 @@ namespace OpenTK.Platform.SDL2
public void ProcessWheelEvent(MouseWheelEvent wheel) public void ProcessWheelEvent(MouseWheelEvent wheel)
{ {
state.WheelPrecise += wheel.Y; state.SetScrollRelative(0, wheel.Y);
mice[0].WheelPrecise += wheel.Y;
} }
public void ProcessMouseEvent(MouseMotionEvent motion) public void ProcessMouseEvent(MouseMotionEvent motion)
{ {
state.X += motion.Xrel; state.X += motion.Xrel;
state.Y += motion.Yrel; state.Y += motion.Yrel;
mice[0].Position = new Point(motion.X, motion.Y);
} }
public void ProcessMouseEvent(MouseButtonEvent button) public void ProcessMouseEvent(MouseButtonEvent button)
{ {
bool pressed = button.State == State.Pressed; bool pressed = button.State == State.Pressed;
SetButtonState(TranslateButton(button.Button), pressed); SetButtonState(TranslateButton(button.Button), pressed);
mice[0][TranslateButton(button.Button)] = pressed;
}
#endregion
#region IMouseDriver Members
public IList<MouseDevice> Mouse
{
get
{
return mice_readonly;
}
} }
#endregion #endregion

View file

@ -41,7 +41,7 @@ using System.Text;
namespace OpenTK.Platform.SDL2 namespace OpenTK.Platform.SDL2
{ {
class Sdl2NativeWindow : INativeWindow, IInputDriver class Sdl2NativeWindow : NativeWindowBase
{ {
readonly object sync = new object(); readonly object sync = new object();
@ -66,25 +66,14 @@ namespace OpenTK.Platform.SDL2
// to .Net UTF16 strings // to .Net UTF16 strings
char[] DecodeTextBuffer = new char[32]; char[] DecodeTextBuffer = new char[32];
// Argument for KeyPress event (allocated once to avoid runtime allocations)
readonly KeyPressEventArgs keypress_args = new KeyPressEventArgs('\0');
// Argument for KeyDown and KeyUp events (allocated once to avoid runtime allocations)
readonly KeyboardKeyEventArgs key_args = new KeyboardKeyEventArgs();
readonly IInputDriver input_driver;
static readonly Dictionary<uint, Sdl2NativeWindow> windows = static readonly Dictionary<uint, Sdl2NativeWindow> windows =
new Dictionary<uint, Sdl2NativeWindow>(); new Dictionary<uint, Sdl2NativeWindow>();
public Sdl2NativeWindow(int x, int y, int width, int height, 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) lock (sync)
{ {
this.input_driver = input_driver;
var bounds = device.Bounds; var bounds = device.Bounds;
var flags = TranslateFlags(options); var flags = TranslateFlags(options);
flags |= WindowFlags.OPENGL; flags |= WindowFlags.OPENGL;
@ -180,7 +169,7 @@ namespace OpenTK.Platform.SDL2
case EventType.MOUSEBUTTONUP: case EventType.MOUSEBUTTONUP:
if (windows.TryGetValue(ev.Button.WindowID, out window)) if (windows.TryGetValue(ev.Button.WindowID, out window))
{ {
ProcessButtonEvent(window, ev); ProcessMouseButtonEvent(window, ev.Button);
processed = true; processed = true;
} }
break; break;
@ -188,7 +177,7 @@ namespace OpenTK.Platform.SDL2
case EventType.MOUSEMOTION: case EventType.MOUSEMOTION:
if (windows.TryGetValue(ev.Motion.WindowID, out window)) if (windows.TryGetValue(ev.Motion.WindowID, out window))
{ {
ProcessMotionEvent(window, ev); ProcessMouseMotionEvent(window, ev.Motion);
processed = true; processed = true;
} }
break; break;
@ -196,7 +185,7 @@ namespace OpenTK.Platform.SDL2
case EventType.MOUSEWHEEL: case EventType.MOUSEWHEEL:
if (windows.TryGetValue(ev.Wheel.WindowID, out window)) if (windows.TryGetValue(ev.Wheel.WindowID, out window))
{ {
ProcessWheelEvent(window, ev); ProcessMouseWheelEvent(window, ev.Wheel);
processed = true; processed = true;
} }
break; break;
@ -214,9 +203,9 @@ namespace OpenTK.Platform.SDL2
return processed ? 0 : 1; return processed ? 0 : 1;
} }
static void ProcessButtonEvent(Sdl2NativeWindow window, Event ev) static void ProcessMouseButtonEvent(Sdl2NativeWindow window, MouseButtonEvent ev)
{ {
bool button_pressed = ev.Button.State == State.Pressed; bool button_pressed = ev.State == State.Pressed;
// We need MouseUp events to be reported even if they occur // We need MouseUp events to be reported even if they occur
// outside the window. SetWindowGrab ensures we get them. // outside the window. SetWindowGrab ensures we get them.
@ -225,24 +214,30 @@ namespace OpenTK.Platform.SDL2
SDL.SetWindowGrab(window.window.Handle, SDL.SetWindowGrab(window.window.Handle,
button_pressed ? true : false); button_pressed ? true : false);
} }
MouseButton button = Sdl2Mouse.TranslateButton(ev.Button);
if (button_pressed)
{
window.OnMouseDown(button);
}
else
{
window.OnMouseUp(button);
}
} }
static void ProcessKeyEvent(Sdl2NativeWindow window, Event ev) static void ProcessKeyEvent(Sdl2NativeWindow window, Event ev)
{ {
bool key_pressed = ev.Key.State == State.Pressed; bool key_pressed = ev.Key.State == State.Pressed;
var key = ev.Key.Keysym; Key key = TranslateKey(ev.Key.Keysym.Scancode);
window.key_args.Key = TranslateKey(key.Scancode);
window.key_args.ScanCode = (uint)key.Scancode;
window.key_args.Modifiers = window.input_driver.Keyboard[0].GetModifiers();
if (key_pressed) if (key_pressed)
{ {
window.KeyDown(window, window.key_args); window.OnKeyDown(key, ev.Key.Repeat > 0);
} }
else else
{ {
window.KeyUp(window, window.key_args); window.OnKeyUp(key);
} }
//window.keyboard.SetKey(TranslateKey(key.scancode), (uint)key.scancode, key_pressed);
} }
static unsafe void ProcessTextInputEvent(Sdl2NativeWindow window, TextInputEvent ev) static unsafe void ProcessTextInputEvent(Sdl2NativeWindow window, TextInputEvent ev)
@ -273,21 +268,21 @@ namespace OpenTK.Platform.SDL2
for (int i = 0; i < decoded_length; i++) for (int i = 0; i < decoded_length; i++)
{ {
window.keypress_args.KeyChar = window.DecodeTextBuffer[i]; window.OnKeyPress(window.DecodeTextBuffer[i]);
window.KeyPress(window, window.keypress_args);
} }
} }
static void ProcessMotionEvent(Sdl2NativeWindow window, Event ev) static void ProcessMouseMotionEvent(Sdl2NativeWindow window, MouseMotionEvent ev)
{ {
float scale = window.ClientSize.Width / (float)window.Size.Width; float scale = window.ClientSize.Width / (float)window.Size.Width;
//window.mouse.Position = new Point( window.OnMouseMove(
// (int)(ev.motion.x * scale), (int)(ev.motion.y * scale)); (int)Math.Round(ev.X * scale),
(int)Math.Round(ev.Y * scale));
} }
static void ProcessWheelEvent(Sdl2NativeWindow window, Event ev) static void ProcessMouseWheelEvent(Sdl2NativeWindow window, MouseWheelEvent ev)
{ {
//window.mouse.Wheel += ev.wheel.y; window.OnMouseWheel(ev.X, ev.Y);
} }
static void ProcessWindowEvent(Sdl2NativeWindow window, WindowEvent e) static void ProcessWindowEvent(Sdl2NativeWindow window, WindowEvent e)
@ -299,7 +294,7 @@ namespace OpenTK.Platform.SDL2
try try
{ {
window.is_in_closing_event = true; window.is_in_closing_event = true;
window.Closing(window, close_args); window.OnClosing(close_args);
} }
finally finally
{ {
@ -308,17 +303,17 @@ namespace OpenTK.Platform.SDL2
if (!close_args.Cancel) if (!close_args.Cancel)
{ {
window.Closed(window, EventArgs.Empty); window.OnClosed(EventArgs.Empty);
window.must_destroy = true; window.must_destroy = true;
} }
break; break;
case WindowEventID.ENTER: case WindowEventID.ENTER:
window.MouseEnter(window, EventArgs.Empty); window.OnMouseEnter(EventArgs.Empty);
break; break;
case WindowEventID.LEAVE: case WindowEventID.LEAVE:
window.MouseLeave(window, EventArgs.Empty); window.OnMouseLeave(EventArgs.Empty);
break; break;
case WindowEventID.EXPOSED: case WindowEventID.EXPOSED:
@ -327,47 +322,47 @@ namespace OpenTK.Platform.SDL2
case WindowEventID.FOCUS_GAINED: case WindowEventID.FOCUS_GAINED:
window.is_focused = true; window.is_focused = true;
window.FocusedChanged(window, EventArgs.Empty); window.OnFocusedChanged(EventArgs.Empty);
break; break;
case WindowEventID.FOCUS_LOST: case WindowEventID.FOCUS_LOST:
window.is_focused = false; window.is_focused = false;
window.FocusedChanged(window, EventArgs.Empty); window.OnFocusedChanged(EventArgs.Empty);
break; break;
case WindowEventID.HIDDEN: case WindowEventID.HIDDEN:
window.is_visible = false; window.is_visible = false;
window.VisibleChanged(window, EventArgs.Empty); window.OnVisibleChanged(EventArgs.Empty);
break; break;
case WindowEventID.SHOWN: case WindowEventID.SHOWN:
window.is_visible = true; window.is_visible = true;
window.VisibleChanged(window, EventArgs.Empty); window.OnVisibleChanged(EventArgs.Empty);
break; break;
case WindowEventID.MAXIMIZED: case WindowEventID.MAXIMIZED:
window.window_state = WindowState.Maximized; window.window_state = WindowState.Maximized;
window.WindowStateChanged(window, EventArgs.Empty); window.OnWindowStateChanged(EventArgs.Empty);
break; break;
case WindowEventID.MINIMIZED: case WindowEventID.MINIMIZED:
window.previous_window_state = window.window_state; window.previous_window_state = window.window_state;
window.window_state = WindowState.Minimized; window.window_state = WindowState.Minimized;
window.WindowStateChanged(window, EventArgs.Empty); window.OnWindowStateChanged(EventArgs.Empty);
break; break;
case WindowEventID.RESTORED: case WindowEventID.RESTORED:
window.window_state = window.previous_window_state; window.window_state = window.previous_window_state;
window.WindowStateChanged(window, EventArgs.Empty); window.OnWindowStateChanged(EventArgs.Empty);
break; break;
case WindowEventID.MOVED: case WindowEventID.MOVED:
window.Move(window, EventArgs.Empty); window.OnMove(EventArgs.Empty);
break; break;
case WindowEventID.RESIZED: case WindowEventID.RESIZED:
case WindowEventID.SIZE_CHANGED: case WindowEventID.SIZE_CHANGED:
window.Resize(window, EventArgs.Empty); window.OnResize(EventArgs.Empty);
break; break;
default: default:
@ -402,6 +397,16 @@ namespace OpenTK.Platform.SDL2
SDL.ShowCursor(!grab); SDL.ShowCursor(!grab);
SDL.SetWindowGrab(window.Handle, grab); SDL.SetWindowGrab(window.Handle, grab);
SDL.SetRelativeMouseMode(grab); SDL.SetRelativeMouseMode(grab);
if (!grab)
{
// Move the cursor to the current position
// in order to avoid a sudden jump when it
// becomes visible again
float scale = Width / (float)Size.Width;
SDL.WarpMouseInWindow(window.Handle,
(int)Math.Round(MouseState.X / scale),
(int)Math.Round(MouseState.Y / scale));
}
} }
// Hack to force WindowState events to be pumped // Hack to force WindowState events to be pumped
@ -443,24 +448,7 @@ namespace OpenTK.Platform.SDL2
#region INativeWindow Members #region INativeWindow Members
public event EventHandler<EventArgs> Move = delegate { }; public override MouseCursor Cursor
public event EventHandler<EventArgs> Resize = delegate { };
public event EventHandler<System.ComponentModel.CancelEventArgs> Closing = delegate { };
public event EventHandler<EventArgs> Closed = delegate { };
public event EventHandler<EventArgs> Disposed = delegate { };
public event EventHandler<EventArgs> IconChanged = delegate { };
public event EventHandler<EventArgs> TitleChanged = delegate { };
public event EventHandler<EventArgs> VisibleChanged = delegate { };
public event EventHandler<EventArgs> FocusedChanged = delegate { };
public event EventHandler<EventArgs> WindowBorderChanged = delegate { };
public event EventHandler<EventArgs> WindowStateChanged = delegate { };
public event EventHandler<KeyboardKeyEventArgs> KeyDown = delegate { };
public event EventHandler<KeyPressEventArgs> KeyPress = delegate { };
public event EventHandler<KeyboardKeyEventArgs> KeyUp = delegate { };
public event EventHandler<EventArgs> MouseEnter = delegate { };
public event EventHandler<EventArgs> MouseLeave = delegate { };
public MouseCursor Cursor
{ {
get get
{ {
@ -540,7 +528,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public void Close() public override void Close()
{ {
lock (sync) lock (sync)
{ {
@ -560,8 +548,9 @@ namespace OpenTK.Platform.SDL2
} }
} }
public void ProcessEvents() public override void ProcessEvents()
{ {
base.ProcessEvents();
lock (sync) lock (sync)
{ {
if (Exists) if (Exists)
@ -581,21 +570,21 @@ namespace OpenTK.Platform.SDL2
} }
} }
public Point PointToClient(Point point) public override Point PointToClient(Point point)
{ {
var origin = DisplayDevice.Default.Bounds.Location; var origin = DisplayDevice.Default.Bounds.Location;
var client = Location; var client = Location;
return new Point(point.X + client.X - origin.X, point.Y + client.Y - origin.Y); return new Point(point.X + client.X - origin.X, point.Y + client.Y - origin.Y);
} }
public Point PointToScreen(Point point) public override Point PointToScreen(Point point)
{ {
var origin = DisplayDevice.Default.Bounds.Location; var origin = DisplayDevice.Default.Bounds.Location;
var client = Location; var client = Location;
return new Point(point.X + origin.X - client.X, point.Y + origin.Y - client.Y); return new Point(point.X + origin.X - client.X, point.Y + origin.Y - client.Y);
} }
public Icon Icon public override Icon Icon
{ {
get get
{ {
@ -639,13 +628,13 @@ namespace OpenTK.Platform.SDL2
} }
icon = value; icon = value;
IconChanged(this, EventArgs.Empty); OnIconChanged(EventArgs.Empty);
} }
} }
} }
} }
public string Title public override string Title
{ {
get get
{ {
@ -671,7 +660,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public bool Focused public override bool Focused
{ {
get get
{ {
@ -679,7 +668,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public bool Visible public override bool Visible
{ {
get get
{ {
@ -700,7 +689,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public bool Exists public override bool Exists
{ {
get get
{ {
@ -708,7 +697,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public IWindowInfo WindowInfo public override IWindowInfo WindowInfo
{ {
get get
{ {
@ -716,7 +705,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public WindowState WindowState public override WindowState WindowState
{ {
get get
{ {
@ -774,7 +763,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public WindowBorder WindowBorder public override WindowBorder WindowBorder
{ {
get get
{ {
@ -810,13 +799,13 @@ namespace OpenTK.Platform.SDL2
if (Exists) if (Exists)
{ {
WindowBorderChanged(this, EventArgs.Empty); OnWindowBorderChanged(EventArgs.Empty);
} }
} }
} }
} }
public Rectangle Bounds public override Rectangle Bounds
{ {
get get
{ {
@ -829,7 +818,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public Point Location public override Point Location
{ {
get get
{ {
@ -856,7 +845,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public Size Size public override Size Size
{ {
get get
{ {
@ -883,67 +872,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public int X public override Size ClientSize
{
get
{
return Location.X;
}
set
{
Location = new Point(value, Y);
}
}
public int Y
{
get
{
return Location.Y;
}
set
{
Location = new Point(X, value);
}
}
public int Width
{
get
{
return ClientSize.Width;
}
set
{
ClientSize = new Size(value, Height);
}
}
public int Height
{
get
{
return ClientSize.Height;
}
set
{
ClientSize = new Size(Width, value);
}
}
public Rectangle ClientRectangle
{
get
{
return new Rectangle(new Point(), ClientSize);
}
set
{
ClientSize = value.Size;
}
}
public Size ClientSize
{ {
get get
{ {
@ -967,15 +896,7 @@ namespace OpenTK.Platform.SDL2
} }
} }
public IInputDriver InputDriver public override bool CursorVisible
{
get
{
return input_driver;
}
}
public bool CursorVisible
{ {
get get
{ {
@ -996,54 +917,9 @@ namespace OpenTK.Platform.SDL2
#endregion #endregion
#region IInputDriver Members
public void Poll()
{
InputDriver.Poll();
}
#endregion
#region IJoystickDriver Members
public IList<JoystickDevice> Joysticks
{
get
{
return InputDriver.Joysticks;
}
}
#endregion
#region IMouseDriver Members
public IList<MouseDevice> Mouse
{
get
{
return InputDriver.Mouse;
}
}
#endregion
#region IKeyboardDriver Members
public IList<KeyboardDevice> Keyboard
{
get
{
return InputDriver.Keyboard;
}
}
#endregion
#region IDisposable implementation #region IDisposable implementation
void Dispose(bool manual) protected override void Dispose(bool manual)
{ {
if (!disposed) if (!disposed)
{ {
@ -1082,17 +958,6 @@ namespace OpenTK.Platform.SDL2
} }
} }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Sdl2NativeWindow()
{
Dispose(true);
}
#endregion #endregion
} }
} }

View file

@ -3591,7 +3591,8 @@ namespace OpenTK.Platform.Windows
BUTTON_5_DOWN = 0x0100, BUTTON_5_DOWN = 0x0100,
BUTTON_5_UP = 0x0200, BUTTON_5_UP = 0x0200,
WHEEL = 0x0400 WHEEL = 0x0400,
HWHEEL = 0x0800,
} }
#endregion #endregion
@ -4197,7 +4198,6 @@ namespace OpenTK.Platform.Windows
MBUTTONUP = 0x0208, MBUTTONUP = 0x0208,
MBUTTONDBLCLK = 0x0209, MBUTTONDBLCLK = 0x0209,
MOUSEWHEEL = 0x020A, MOUSEWHEEL = 0x020A,
MOUSELAST = 0x020D,
/// <summary> /// <summary>
/// Windows 2000 and higher only. /// Windows 2000 and higher only.
/// </summary> /// </summary>
@ -4210,6 +4210,10 @@ namespace OpenTK.Platform.Windows
/// Windows 2000 and higher only. /// Windows 2000 and higher only.
/// </summary> /// </summary>
XBUTTONDBLCLK = 0x020D, XBUTTONDBLCLK = 0x020D,
/// <summary>
/// Windows Vista and higher only.
/// </summary>
MOUSEHWHEEL = 0x020E,
PARENTNOTIFY = 0x0210, PARENTNOTIFY = 0x0210,
ENTERMENULOOP = 0x0211, ENTERMENULOOP = 0x0211,
EXITMENULOOP = 0x0212, EXITMENULOOP = 0x0212,

View file

@ -44,7 +44,7 @@ namespace OpenTK.Platform.Windows
/// Drives GameWindow on Windows. /// Drives GameWindow on Windows.
/// This class supports OpenTK, and is not intended for use by OpenTK programs. /// This class supports OpenTK, and is not intended for use by OpenTK programs.
/// </summary> /// </summary>
internal sealed class WinGLNative : INativeWindow, IInputDriver internal sealed class WinGLNative : NativeWindowBase
{ {
#region Fields #region Fields
@ -82,12 +82,6 @@ namespace OpenTK.Platform.Windows
const ClassStyle DefaultClassStyle = ClassStyle.OwnDC; const ClassStyle DefaultClassStyle = ClassStyle.OwnDC;
// Used for IInputDriver implementation
IJoystickDriver joystick_driver = Factory.Default.CreateLegacyJoystickDriver();
KeyboardDevice keyboard = new KeyboardDevice();
MouseDevice mouse = new MouseDevice();
IList<KeyboardDevice> keyboards = new List<KeyboardDevice>(1);
IList<MouseDevice> mice = new List<MouseDevice>(1);
const long ExtendedBit = 1 << 24; // Used to distinguish left and right control, alt and enter keys. const long ExtendedBit = 1 << 24; // Used to distinguish left and right control, alt and enter keys.
public static readonly uint ShiftLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LSHIFT, 0); public static readonly uint ShiftLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LSHIFT, 0);
@ -97,10 +91,6 @@ namespace OpenTK.Platform.Windows
public static readonly uint AltLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LMENU, 0); public static readonly uint AltLeftScanCode = Functions.MapVirtualKey(VirtualKeys.LMENU, 0);
public static readonly uint AltRightScanCode = Functions.MapVirtualKey(VirtualKeys.RMENU, 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);
MouseCursor cursor = MouseCursor.Default; MouseCursor cursor = MouseCursor.Default;
IntPtr cursor_handle = Functions.LoadCursor(CursorName.Arrow); IntPtr cursor_handle = Functions.LoadCursor(CursorName.Arrow);
int cursor_visible_count = 0; int cursor_visible_count = 0;
@ -160,18 +150,6 @@ namespace OpenTK.Platform.Windows
window); window);
exists = true; exists = true;
keyboard.Description = "Standard Windows keyboard";
keyboard.NumberOfFunctionKeys = 12;
keyboard.NumberOfKeys = 101;
keyboard.NumberOfLeds = 3;
mouse.Description = "Standard Windows mouse";
mouse.NumberOfButtons = 3;
mouse.NumberOfWheels = 1;
keyboards.Add(keyboard);
mice.Add(mouse);
} }
} }
@ -254,7 +232,7 @@ namespace OpenTK.Platform.Windows
focused = (wParam.ToInt64() & 0xFFFF) != 0; focused = (wParam.ToInt64() & 0xFFFF) != 0;
if (new_focused_state != Focused) if (new_focused_state != Focused)
FocusedChanged(this, EventArgs.Empty); OnFocusedChanged(EventArgs.Empty);
} }
void HandleEnterModalLoop(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleEnterModalLoop(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
@ -292,7 +270,7 @@ namespace OpenTK.Platform.Windows
if (Location != new_location) if (Location != new_location)
{ {
bounds.Location = new_location; bounds.Location = new_location;
Move(this, EventArgs.Empty); OnMove(EventArgs.Empty);
} }
Size new_size = new Size(pos->cx, pos->cy); Size new_size = new Size(pos->cx, pos->cy);
@ -310,7 +288,7 @@ namespace OpenTK.Platform.Windows
SetWindowPosFlags.NOACTIVATE | SetWindowPosFlags.NOSENDCHANGING); SetWindowPosFlags.NOACTIVATE | SetWindowPosFlags.NOSENDCHANGING);
if (suppress_resize <= 0) if (suppress_resize <= 0)
Resize(this, EventArgs.Empty); OnResize(EventArgs.Empty);
} }
if (!is_in_modal_loop) if (!is_in_modal_loop)
@ -352,7 +330,7 @@ namespace OpenTK.Platform.Windows
GrabCursor(); GrabCursor();
windowBorder = new_border; windowBorder = new_border;
WindowBorderChanged(this, EventArgs.Empty); OnWindowBorderChanged(EventArgs.Empty);
} }
} }
@ -380,7 +358,7 @@ namespace OpenTK.Platform.Windows
if (new_state != windowState) if (new_state != windowState)
{ {
windowState = new_state; windowState = new_state;
WindowStateChanged(this, EventArgs.Empty); OnWindowStateChanged(EventArgs.Empty);
// Ensure cursor remains grabbed // Ensure cursor remains grabbed
if (!CursorVisible) if (!CursorVisible)
@ -415,8 +393,7 @@ namespace OpenTK.Platform.Windows
if (!Char.IsControl(c)) if (!Char.IsControl(c))
{ {
key_press.KeyChar = c; OnKeyPress(c);
KeyPress(this, key_press);
} }
} }
@ -442,8 +419,7 @@ namespace OpenTK.Platform.Windows
}; };
// Max points GetMouseMovePointsEx can return is 64. // Max points GetMouseMovePointsEx can return is 64.
int numPoints = 64; const int numPoints = 64;
MouseMovePoint* movePoints = stackalloc MouseMovePoint[numPoints]; MouseMovePoint* movePoints = stackalloc MouseMovePoint[numPoints];
// GetMouseMovePointsEx fills in movePoints so that the most // GetMouseMovePointsEx fills in movePoints so that the most
@ -459,7 +435,7 @@ namespace OpenTK.Platform.Windows
if (points == 0 || (points == -1 && lastError == Constants.ERROR_POINT_NOT_FOUND)) if (points == 0 || (points == -1 && lastError == Constants.ERROR_POINT_NOT_FOUND))
{ {
// Just use the mouse move position // Just use the mouse move position
mouse.Position = point; OnMouseMove(point.X, point.Y);
} }
else if (points == -1) else if (points == -1)
{ {
@ -468,7 +444,7 @@ namespace OpenTK.Platform.Windows
else else
{ {
// Exclude the current position. // Exclude the current position.
Point currentScreenPosition = new Point(mouse.X, mouse.Y); Point currentScreenPosition = new Point(InputDriver.Mouse[0].X, InputDriver.Mouse[0].Y);
Functions.ClientToScreen(handle, ref currentScreenPosition); Functions.ClientToScreen(handle, ref currentScreenPosition);
// Find the first move point we've already seen. // Find the first move point we've already seen.
@ -497,7 +473,7 @@ namespace OpenTK.Platform.Windows
position.Y -= 65536; position.Y -= 65536;
} }
Functions.ScreenToClient(handle, ref position); Functions.ScreenToClient(handle, ref position);
mouse.Position = position; OnMouseMove(position.X, position.Y);
} }
} }
mouse_last_timestamp = timestamp; mouse_last_timestamp = timestamp;
@ -510,7 +486,7 @@ namespace OpenTK.Platform.Windows
mouse_outside_window = false; mouse_outside_window = false;
EnableMouseTracking(); EnableMouseTracking();
MouseEnter(this, EventArgs.Empty); OnMouseEnter(EventArgs.Empty);
} }
} }
@ -519,64 +495,75 @@ namespace OpenTK.Platform.Windows
mouse_outside_window = true; mouse_outside_window = true;
// Mouse tracking is disabled automatically by the OS // Mouse tracking is disabled automatically by the OS
MouseLeave(this, EventArgs.Empty); OnMouseLeave(EventArgs.Empty);
} }
void HandleMouseWheel(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleMouseWheel(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
// This is due to inconsistent behavior of the WParam value on 64bit arch, whese // This is due to inconsistent behavior of the WParam value on 64bit arch, whese
// wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000 // wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000
mouse.WheelPrecise += ((long)wParam << 32 >> 48) / 120.0f; OnMouseWheel(0, ((long)wParam << 32 >> 48) / 120.0f);
}
void HandleMouseHWheel(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
// This is due to inconsistent behavior of the WParam value on 64bit arch, whese
// wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000
OnMouseWheel(((long)wParam << 32 >> 48) / 120.0f, 0);
} }
void HandleLButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleLButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.SetCapture(window.Handle); Functions.SetCapture(window.Handle);
mouse[MouseButton.Left] = true; OnMouseDown(MouseButton.Left);
} }
void HandleMButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleMButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.SetCapture(window.Handle); Functions.SetCapture(window.Handle);
mouse[MouseButton.Middle] = true; OnMouseDown(MouseButton.Middle);
} }
void HandleRButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleRButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.SetCapture(window.Handle); Functions.SetCapture(window.Handle);
mouse[MouseButton.Right] = true; OnMouseDown(MouseButton.Right);
} }
void HandleXButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleXButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.SetCapture(window.Handle); Functions.SetCapture(window.Handle);
mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ? MouseButton button =
MouseButton.Button1 : MouseButton.Button2] = true; ((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2;
OnMouseDown(button);
} }
void HandleLButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleLButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.ReleaseCapture(); Functions.ReleaseCapture();
mouse[MouseButton.Left] = false; OnMouseUp(MouseButton.Left);
} }
void HandleMButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleMButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.ReleaseCapture(); Functions.ReleaseCapture();
mouse[MouseButton.Middle] = false; OnMouseUp(MouseButton.Middle);
} }
void HandleRButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleRButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.ReleaseCapture(); Functions.ReleaseCapture();
mouse[MouseButton.Right] = false; OnMouseUp(MouseButton.Right);
} }
void HandleXButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleXButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.ReleaseCapture(); Functions.ReleaseCapture();
mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ? MouseButton button =
MouseButton.Button1 : MouseButton.Button2] = false; ((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2;
OnMouseUp(button);
} }
void HandleKeyboard(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleKeyboard(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
@ -593,33 +580,28 @@ namespace OpenTK.Platform.Windows
// In this case, both keys will be reported as pressed. // In this case, both keys will be reported as pressed.
bool extended = (lParam.ToInt64() & ExtendedBit) != 0; bool extended = (lParam.ToInt64() & ExtendedBit) != 0;
short scancode = (short)((lParam.ToInt64() >> 16) & 0xFF); short scancode = (short)((lParam.ToInt64() >> 16) & 0xff);
//ushort repeat_count = unchecked((ushort)((ulong)lParam.ToInt64() & 0xffffu));
VirtualKeys vkey = (VirtualKeys)wParam; VirtualKeys vkey = (VirtualKeys)wParam;
bool is_valid; bool is_valid;
Key key = WinKeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid); Key key = WinKeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid);
if (is_valid) if (is_valid)
{ {
keyboard.SetKey(key, (byte)scancode, pressed);
if (pressed) if (pressed)
{ {
key_down.Key = key; //OnKeyDown(key, repeat_count > 0);
key_down.Modifiers = keyboard.GetModifiers(); OnKeyDown(key, KeyboardState[key]);
KeyDown(this, key_down);
} }
else else
{ {
key_up.Key = key; OnKeyUp(key);
key_up.Modifiers = keyboard.GetModifiers();
KeyUp(this, key_up);
} }
} }
} }
void HandleKillFocus(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleKillFocus(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
keyboard.ClearKeys();
} }
void HandleCreate(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleCreate(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
@ -644,7 +626,7 @@ namespace OpenTK.Platform.Windows
{ {
System.ComponentModel.CancelEventArgs e = new System.ComponentModel.CancelEventArgs(); System.ComponentModel.CancelEventArgs e = new System.ComponentModel.CancelEventArgs();
Closing(this, e); OnClosing(e);
if (!e.Cancel) if (!e.Cancel)
{ {
@ -663,7 +645,7 @@ namespace OpenTK.Platform.Windows
window.Dispose(); window.Dispose();
child_window.Dispose(); child_window.Dispose();
Closed(this, EventArgs.Empty); OnClosed(EventArgs.Empty);
} }
#endregion #endregion
@ -731,6 +713,10 @@ namespace OpenTK.Platform.Windows
HandleMouseWheel(handle, message, wParam, lParam); HandleMouseWheel(handle, message, wParam, lParam);
break; break;
case WindowMessage.MOUSEHWHEEL:
HandleMouseHWheel(handle, message, wParam, lParam);
break;
case WindowMessage.LBUTTONDOWN: case WindowMessage.LBUTTONDOWN:
HandleLButtonDown(handle, message, wParam, lParam); HandleLButtonDown(handle, message, wParam, lParam);
break; break;
@ -927,7 +913,6 @@ namespace OpenTK.Platform.Windows
{ {
suppress_resize++; suppress_resize++;
WindowBorder = WindowBorder.Hidden; WindowBorder = WindowBorder.Hidden;
ProcessEvents();
suppress_resize--; suppress_resize--;
} }
@ -938,7 +923,6 @@ namespace OpenTK.Platform.Windows
deferred_window_border.HasValue ? deferred_window_border.Value : deferred_window_border.HasValue ? deferred_window_border.Value :
previous_window_border.HasValue ? previous_window_border.Value : previous_window_border.HasValue ? previous_window_border.Value :
WindowBorder; WindowBorder;
ProcessEvents();
suppress_resize--; suppress_resize--;
deferred_window_border = previous_window_border = null; deferred_window_border = previous_window_border = null;
} }
@ -947,7 +931,6 @@ namespace OpenTK.Platform.Windows
{ {
suppress_resize++; suppress_resize++;
WindowState = WindowState.Normal; WindowState = WindowState.Normal;
ProcessEvents();
suppress_resize--; suppress_resize--;
} }
@ -977,7 +960,7 @@ namespace OpenTK.Platform.Windows
#region Bounds #region Bounds
public Rectangle Bounds public override Rectangle Bounds
{ {
get { return bounds; } get { return bounds; }
set set
@ -991,7 +974,7 @@ namespace OpenTK.Platform.Windows
#region Location #region Location
public Point Location public override Point Location
{ {
get { return Bounds.Location; } get { return Bounds.Location; }
set set
@ -1005,7 +988,7 @@ namespace OpenTK.Platform.Windows
#region Size #region Size
public Size Size public override Size Size
{ {
get { return Bounds.Size; } get { return Bounds.Size; }
set set
@ -1017,36 +1000,13 @@ namespace OpenTK.Platform.Windows
#endregion #endregion
#region ClientRectangle
public Rectangle ClientRectangle
{
get
{
if (client_rectangle.Width == 0)
client_rectangle.Width = 1;
if (client_rectangle.Height == 0)
client_rectangle.Height = 1;
return client_rectangle;
}
set
{
WindowStyle style = (WindowStyle)Functions.GetWindowLong(window.Handle, GetWindowLongOffsets.STYLE);
Win32Rectangle rect = Win32Rectangle.From(value);
Functions.AdjustWindowRect(ref rect, style, false);
Size = new Size(rect.Width, rect.Height);
}
}
#endregion
#region ClientSize #region ClientSize
public Size ClientSize public override Size ClientSize
{ {
get get
{ {
return ClientRectangle.Size; return client_rectangle.Size;
} }
set set
{ {
@ -1059,49 +1019,9 @@ namespace OpenTK.Platform.Windows
#endregion #endregion
#region Width
public int Width
{
get { return ClientRectangle.Width; }
set { ClientRectangle = new Rectangle(0, 0, value, Height); }
}
#endregion
#region Height
public int Height
{
get { return ClientRectangle.Height; }
set { ClientRectangle = new Rectangle(0, 0, Width, value); }
}
#endregion
#region X
public int X
{
get { return Location.X; }
set { Location = new Point(value, Y); }
}
#endregion
#region Y
public int Y
{
get { return Location.Y; }
set { Location = new Point(X, value); }
}
#endregion
#region Icon #region Icon
public Icon Icon public override Icon Icon
{ {
get get
{ {
@ -1117,7 +1037,7 @@ namespace OpenTK.Platform.Windows
Functions.SendMessage(window.Handle, WindowMessage.SETICON, (IntPtr)0, 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); Functions.SendMessage(window.Handle, WindowMessage.SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle);
} }
IconChanged(this, EventArgs.Empty); OnIconChanged(EventArgs.Empty);
} }
} }
} }
@ -1126,7 +1046,7 @@ namespace OpenTK.Platform.Windows
#region Focused #region Focused
public bool Focused public override bool Focused
{ {
get { return focused; } get { return focused; }
} }
@ -1136,7 +1056,7 @@ namespace OpenTK.Platform.Windows
#region Title #region Title
StringBuilder sb_title = new StringBuilder(256); StringBuilder sb_title = new StringBuilder(256);
public string Title public override string Title
{ {
get get
{ {
@ -1151,7 +1071,7 @@ namespace OpenTK.Platform.Windows
{ {
if (!Functions.SetWindowText(window.Handle, value)) if (!Functions.SetWindowText(window.Handle, value))
Debug.Print("Failed to change window title (window:{0}, new title:{1}, reason:{2}).", window.Handle, value, Marshal.GetLastWin32Error()); Debug.Print("Failed to change window title (window:{0}, new title:{1}, reason:{2}).", window.Handle, value, Marshal.GetLastWin32Error());
TitleChanged(this, EventArgs.Empty); OnTitleChanged(EventArgs.Empty);
} }
} }
} }
@ -1160,7 +1080,7 @@ namespace OpenTK.Platform.Windows
#region Visible #region Visible
public bool Visible public override bool Visible
{ {
get get
{ {
@ -1184,7 +1104,7 @@ namespace OpenTK.Platform.Windows
Functions.ShowWindow(window.Handle, ShowWindowCommand.HIDE); Functions.ShowWindow(window.Handle, ShowWindowCommand.HIDE);
} }
VisibleChanged(this, EventArgs.Empty); OnVisibleChanged(EventArgs.Empty);
} }
} }
} }
@ -1193,13 +1113,13 @@ namespace OpenTK.Platform.Windows
#region Exists #region Exists
public bool Exists { get { return exists; } } public override bool Exists { get { return exists; } }
#endregion #endregion
#region Cursor #region Cursor
public MouseCursor Cursor public override MouseCursor Cursor
{ {
get get
{ {
@ -1271,7 +1191,7 @@ namespace OpenTK.Platform.Windows
#region CursorVisible #region CursorVisible
public bool CursorVisible public override bool CursorVisible
{ {
get { return cursor_visible_count >= 0; } // Not used get { return cursor_visible_count >= 0; } // Not used
set set
@ -1303,7 +1223,7 @@ namespace OpenTK.Platform.Windows
#region Close #region Close
public void Close() public override void Close()
{ {
Functions.PostMessage(window.Handle, WindowMessage.CLOSE, IntPtr.Zero, IntPtr.Zero); Functions.PostMessage(window.Handle, WindowMessage.CLOSE, IntPtr.Zero, IntPtr.Zero);
} }
@ -1312,7 +1232,7 @@ namespace OpenTK.Platform.Windows
#region public WindowState WindowState #region public WindowState WindowState
public WindowState WindowState public override WindowState WindowState
{ {
get get
{ {
@ -1325,12 +1245,12 @@ namespace OpenTK.Platform.Windows
ShowWindowCommand command = 0; ShowWindowCommand command = 0;
bool exiting_fullscreen = false; bool exiting_fullscreen = false;
borderless_maximized_window_state = false;
switch (value) switch (value)
{ {
case WindowState.Normal: case WindowState.Normal:
command = ShowWindowCommand.RESTORE; command = ShowWindowCommand.RESTORE;
borderless_maximized_window_state = false;
// If we are leaving fullscreen mode we need to restore the border. // If we are leaving fullscreen mode we need to restore the border.
if (WindowState == WindowState.Fullscreen) if (WindowState == WindowState.Fullscreen)
@ -1358,6 +1278,7 @@ namespace OpenTK.Platform.Windows
} }
else else
{ {
borderless_maximized_window_state = false;
command = ShowWindowCommand.MAXIMIZE; command = ShowWindowCommand.MAXIMIZE;
} }
break; break;
@ -1406,7 +1327,7 @@ namespace OpenTK.Platform.Windows
#region public WindowBorder WindowBorder #region public WindowBorder WindowBorder
public WindowBorder WindowBorder public override WindowBorder WindowBorder
{ {
get get
{ {
@ -1500,7 +1421,7 @@ namespace OpenTK.Platform.Windows
#region PointToClient #region PointToClient
public Point PointToClient(Point point) public override Point PointToClient(Point point)
{ {
if (!Functions.ScreenToClient(window.Handle, ref point)) if (!Functions.ScreenToClient(window.Handle, ref point))
throw new InvalidOperationException(String.Format( throw new InvalidOperationException(String.Format(
@ -1514,7 +1435,7 @@ namespace OpenTK.Platform.Windows
#region PointToScreen #region PointToScreen
public Point PointToScreen(Point point) public override Point PointToScreen(Point point)
{ {
if (!Functions.ClientToScreen(window.Handle, ref point)) if (!Functions.ClientToScreen(window.Handle, ref point))
throw new InvalidOperationException(String.Format( throw new InvalidOperationException(String.Format(
@ -1526,27 +1447,6 @@ namespace OpenTK.Platform.Windows
#endregion #endregion
#region Events
public event EventHandler<EventArgs> Move = delegate { };
public event EventHandler<EventArgs> Resize = delegate { };
public event EventHandler<System.ComponentModel.CancelEventArgs> Closing = delegate { };
public event EventHandler<EventArgs> Closed = delegate { };
public event EventHandler<EventArgs> Disposed = delegate { };
public event EventHandler<EventArgs> IconChanged = delegate { };
public event EventHandler<EventArgs> TitleChanged = delegate { };
public event EventHandler<EventArgs> VisibleChanged = delegate { };
public event EventHandler<EventArgs> FocusedChanged = delegate { };
public event EventHandler<EventArgs> WindowBorderChanged = delegate { };
public event EventHandler<EventArgs> WindowStateChanged = delegate { };
public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyDown = delegate { };
public event EventHandler<KeyPressEventArgs> KeyPress = delegate { };
public event EventHandler<OpenTK.Input.KeyboardKeyEventArgs> KeyUp = delegate { };
public event EventHandler<EventArgs> MouseEnter = delegate { };
public event EventHandler<EventArgs> MouseLeave = delegate { };
#endregion
#endregion #endregion
#region INativeGLWindow Members #region INativeGLWindow Members
@ -1554,8 +1454,9 @@ namespace OpenTK.Platform.Windows
#region public void ProcessEvents() #region public void ProcessEvents()
MSG msg; MSG msg;
public void ProcessEvents() public override void ProcessEvents()
{ {
base.ProcessEvents();
while (Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, PeekMessageFlags.Remove)) while (Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, PeekMessageFlags.Remove))
{ {
Functions.TranslateMessage(ref msg); Functions.TranslateMessage(ref msg);
@ -1565,18 +1466,9 @@ namespace OpenTK.Platform.Windows
#endregion #endregion
#region public IInputDriver InputDriver
public IInputDriver InputDriver
{
get { return this; }
}
#endregion
#region public IWindowInfo WindowInfo #region public IWindowInfo WindowInfo
public IWindowInfo WindowInfo public override IWindowInfo WindowInfo
{ {
get { return child_window; } get { return child_window; }
} }
@ -1585,62 +1477,9 @@ namespace OpenTK.Platform.Windows
#endregion #endregion
#region IInputDriver Members
public void Poll()
{
if (joystick_driver is WinMMJoystick)
(joystick_driver as WinMMJoystick).Poll();
}
#endregion
#region IKeyboardDriver Members
public IList<KeyboardDevice> Keyboard
{
get { return keyboards; }
}
public KeyboardState GetState()
{
throw new NotImplementedException();
}
public KeyboardState GetState(int index)
{
throw new NotImplementedException();
}
#endregion
#region IMouseDriver Members
public IList<MouseDevice> Mouse
{
get { return mice; }
}
#endregion
#region IJoystickDriver Members
public IList<JoystickDevice> Joysticks
{
get { return joystick_driver.Joysticks; }
}
#endregion
#region IDisposable Members #region IDisposable Members
public void Dispose() protected override void Dispose(bool calledManually)
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool calledManually)
{ {
if (!disposed) if (!disposed)
{ {
@ -1662,16 +1501,11 @@ namespace OpenTK.Platform.Windows
Debug.Print("[Warning] INativeWindow leaked ({0}). Did you forget to call INativeWindow.Dispose()?", this); Debug.Print("[Warning] INativeWindow leaked ({0}). Did you forget to call INativeWindow.Dispose()?", this);
} }
Disposed(this, EventArgs.Empty); OnDisposed(EventArgs.Empty);
disposed = true; disposed = true;
} }
} }
~WinGLNative()
{
Dispose(false);
}
#endregion #endregion
} }
} }

View file

@ -188,7 +188,7 @@ namespace OpenTK.Platform.Windows
if (is_valid) if (is_valid)
{ {
keyboard.SetKeyState(key, (byte)scancode, pressed); keyboard.SetKeyState(key, pressed);
processed = true; processed = true;
} }

View file

@ -227,7 +227,10 @@ namespace OpenTK.Platform.Windows
} }
if ((raw.ButtonFlags & RawInputMouseState.WHEEL) != 0) if ((raw.ButtonFlags & RawInputMouseState.WHEEL) != 0)
mouse.WheelPrecise += (short)raw.ButtonData / 120.0f; mouse.SetScrollRelative(0, (short)raw.ButtonData / 120.0f);
if ((raw.ButtonFlags & RawInputMouseState.HWHEEL) != 0)
mouse.SetScrollRelative((short)raw.ButtonData / 120.0f, 0);
if ((raw.Flags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) != 0) if ((raw.Flags & RawMouseFlags.MOUSE_MOVE_ABSOLUTE) != 0)
{ {

View file

@ -266,7 +266,14 @@ namespace OpenTK.Platform.X11
static string[] EntryPointNames = new string[] static string[] EntryPointNames = new string[]
{ {
"glXCreateContextAttribs", "glXCreateContextAttribs",
"glXSwapIntervalEXT",
"glXGetSwapIntervalEXT",
"glXSwapIntervalMESA",
"glXGetSwapIntervalMESA",
"glXSwapIntervalOML",
"glXGetSwapIntervalOML",
"glXSwapIntervalSGI", "glXSwapIntervalSGI",
"glXGetSwapIntervalSGI",
}; };
static IntPtr[] EntryPoints = new IntPtr[EntryPointNames.Length]; static IntPtr[] EntryPoints = new IntPtr[EntryPointNames.Length];
@ -405,6 +412,36 @@ namespace OpenTK.Platform.X11
#endregion #endregion
} }
public partial class Ext
{
[AutoGenerated(EntryPoint = "glXSwapIntervalEXT")]
public static ErrorCode SwapInterval(int interval)
{
throw new NotImplementedException();
}
[AutoGenerated(EntryPoint = "glXGetSwapIntervalEXT")]
public static int GetSwapInterval()
{
throw new NotImplementedException();
}
}
public partial class Mesa
{
[AutoGenerated(EntryPoint = "glXSwapIntervalMESA")]
public static ErrorCode SwapInterval(int interval)
{
throw new NotImplementedException();
}
[AutoGenerated(EntryPoint = "glXGetSwapIntervalMESA")]
public static int GetSwapInterval()
{
throw new NotImplementedException();
}
}
public partial class Sgi public partial class Sgi
{ {
[AutoGenerated(EntryPoint = "glXSwapIntervalSGI")] [AutoGenerated(EntryPoint = "glXSwapIntervalSGI")]
@ -412,6 +449,12 @@ namespace OpenTK.Platform.X11
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
[AutoGenerated(EntryPoint = "glXGetSwapIntervalSGI")]
public static int GetSwapInterval()
{
throw new NotImplementedException();
}
} }
[Slot(0)] [Slot(0)]
@ -419,7 +462,22 @@ namespace OpenTK.Platform.X11
internal unsafe static extern IntPtr glXCreateContextAttribsARB(IntPtr display, IntPtr fbconfig, IntPtr share_context, bool direct, int* attribs); internal unsafe static extern IntPtr glXCreateContextAttribsARB(IntPtr display, IntPtr fbconfig, IntPtr share_context, bool direct, int* attribs);
[Slot(1)] [Slot(1)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] [DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern IntPtr glXSwapIntervalSGI(int interval); internal static extern ErrorCode glXSwapIntervalEXT(int interval);
[Slot(2)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern int glXGetSwapIntervalEXT();
[Slot(3)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern ErrorCode glXSwapIntervalMESA(int interval);
[Slot(4)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern int glXGetSwapIntervalMESA();
[Slot(5)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern ErrorCode glXSwapIntervalSGI(int interval);
[Slot(6)]
[DllImport(Library, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
internal static extern int glXGetSwapIntervalSGI();
#endregion #endregion
} }

View file

@ -1707,7 +1707,7 @@ namespace OpenTK.Platform.X11
public double root_y; public double root_y;
public double event_x; public double event_x;
public double event_y; public double event_y;
public int flags; public XIEventFlags flags;
public XIButtonState buttons; public XIButtonState buttons;
public XIValuatorState valuators; public XIValuatorState valuators;
public XIModifierState mods; public XIModifierState mods;
@ -1828,4 +1828,32 @@ namespace OpenTK.Platform.X11
RawButtonReleaseMask = (1 << (int)XIEventType.RawButtonRelease), RawButtonReleaseMask = (1 << (int)XIEventType.RawButtonRelease),
RawMotionMask = (1 << (int)XIEventType.RawMotion), RawMotionMask = (1 << (int)XIEventType.RawMotion),
} }
[Flags]
enum XIKeyEventFlags
{
Repeat = (1 << 16),
}
[Flags]
enum XIPointerEventFlags
{
Emulated = (1 << 16),
}
[Flags]
enum XITouchEventFlags
{
PendingEnd = (1 << 16),
EmulatingPointer = (1 << 17),
}
[Flags]
enum XIEventFlags
{
KeyRepeat = XIKeyEventFlags.Repeat,
PointerEmulated = XIPointerEventFlags.Emulated,
TouchPendingEnd = XITouchEventFlags.PendingEnd,
TouchEmulatingPointer = XITouchEventFlags.EmulatingPointer
}
} }

View file

@ -29,10 +29,13 @@ namespace OpenTK.Platform.X11
// current on window originating from a different display. // current on window originating from a different display.
IntPtr display; IntPtr display;
X11WindowInfo currentWindow; X11WindowInfo currentWindow;
bool vsync_supported; bool vsync_ext_supported;
bool vsync_mesa_supported;
bool vsync_sgi_supported;
bool vsync_tear_supported; bool vsync_tear_supported;
int swap_interval = 1; // As defined in GLX_SGI_swap_control int sgi_swap_interval = 1; // As defined in GLX_SGI_swap_control
readonly X11GraphicsMode ModeSelector = new X11GraphicsMode(); readonly X11GraphicsMode ModeSelector = new X11GraphicsMode();
string extensions = null;
#endregion #endregion
@ -232,7 +235,7 @@ namespace OpenTK.Platform.X11
return result; return result;
} }
static bool SupportsExtension(IntPtr display, X11WindowInfo window, string e) bool SupportsExtension(IntPtr display, X11WindowInfo window, string e)
{ {
if (window == null) if (window == null)
throw new ArgumentNullException("window"); throw new ArgumentNullException("window");
@ -241,15 +244,17 @@ namespace OpenTK.Platform.X11
if (window.Display != display) if (window.Display != display)
throw new InvalidOperationException(); throw new InvalidOperationException();
string extensions = null; if (String.IsNullOrEmpty(extensions))
{
using (new XLock(display)) using (new XLock(display))
{ {
extensions = Glx.QueryExtensionsString(display, window.Screen); extensions = Glx.QueryExtensionsString(display, window.Screen);
} }
}
return !String.IsNullOrEmpty(extensions) && extensions.Contains(e); return !String.IsNullOrEmpty(extensions) && extensions.Contains(e);
} }
static bool SupportsCreateContextAttribs(IntPtr display, X11WindowInfo window) bool SupportsCreateContextAttribs(IntPtr display, X11WindowInfo window)
{ {
return return
SupportsExtension(display, window, "GLX_ARB_create_context") && SupportsExtension(display, window, "GLX_ARB_create_context") &&
@ -354,14 +359,19 @@ namespace OpenTK.Platform.X11
{ {
get get
{ {
if (vsync_supported) using (new XLock(display))
return swap_interval; {
if (vsync_ext_supported)
return Glx.Ext.GetSwapInterval();
else if (vsync_mesa_supported)
return Glx.Mesa.GetSwapInterval();
else if (vsync_sgi_supported)
return sgi_swap_interval;
else else
return 0; return 0;
} }
}
set set
{
if (vsync_supported)
{ {
if (value < 0 && !vsync_tear_supported) if (value < 0 && !vsync_tear_supported)
{ {
@ -370,15 +380,21 @@ namespace OpenTK.Platform.X11
ErrorCode error_code = 0; ErrorCode error_code = 0;
using (new XLock(Display)) using (new XLock(Display))
{
if (vsync_ext_supported)
error_code = Glx.Ext.SwapInterval(value);
else if (vsync_mesa_supported)
error_code = Glx.Mesa.SwapInterval(value);
else if (vsync_sgi_supported)
error_code = Glx.Sgi.SwapInterval(value); error_code = Glx.Sgi.SwapInterval(value);
}
if (error_code == X11.ErrorCode.NO_ERROR) if (error_code == X11.ErrorCode.NO_ERROR)
swap_interval = value; sgi_swap_interval = value;
else else
Debug.Print("VSync = {0} failed, error code: {1}.", value, error_code); Debug.Print("VSync = {0} failed, error code: {1}.", value, error_code);
} }
} }
}
#endregion #endregion
@ -386,12 +402,23 @@ namespace OpenTK.Platform.X11
public override void LoadAll() public override void LoadAll()
{ {
vsync_supported = vsync_ext_supported =
SupportsExtension(display, currentWindow, "GLX_EXT_swap_control") &&
Glx.SupportsFunction("glXSwapIntervalEXT") &&
Glx.SupportsFunction("glXGetSwapIntervalEXT");
vsync_mesa_supported =
SupportsExtension(display, currentWindow, "GLX_MESA_swap_control") &&
Glx.SupportsFunction("glXSwapIntervalMESA") &&
Glx.SupportsFunction("glXGetSwapIntervalMESA");
vsync_sgi_supported =
SupportsExtension(display, currentWindow, "GLX_SGI_swap_control") && SupportsExtension(display, currentWindow, "GLX_SGI_swap_control") &&
Glx.SupportsFunction("glXSwapIntervalSGI"); Glx.SupportsFunction("glXSwapIntervalSGI");
Debug.Print("Context supports vsync: {0}.",
vsync_ext_supported || vsync_mesa_supported || vsync_ext_supported);
vsync_tear_supported = vsync_tear_supported =
SupportsExtension(display, currentWindow, "GLX_EXT_swap_control_tear"); SupportsExtension(display, currentWindow, "GLX_EXT_swap_control_tear");
Debug.Print("Context supports vsync: {0}.", vsync_supported); Debug.Print("Context supports vsync tear: {0}.", vsync_tear_supported);
base.LoadAll(); base.LoadAll();
} }

View file

@ -45,7 +45,7 @@ namespace OpenTK.Platform.X11
/// Drives GameWindow on X11. /// Drives GameWindow on X11.
/// This class supports OpenTK, and is not intended for use by OpenTK programs. /// This class supports OpenTK, and is not intended for use by OpenTK programs.
/// </summary> /// </summary>
internal sealed class X11GLNative : INativeWindow, IDisposable internal sealed class X11GLNative : NativeWindowBase
{ {
// TODO: Disable screensaver. // TODO: Disable screensaver.
// TODO: What happens if we can't disable decorations through motif? // TODO: What happens if we can't disable decorations through motif?
@ -57,11 +57,6 @@ namespace OpenTK.Platform.X11
X11WindowInfo window = new X11WindowInfo(); X11WindowInfo window = new X11WindowInfo();
// Legacy input support
X11Input driver;
KeyboardDevice keyboard;
MouseDevice mouse;
// Window manager hints for fullscreen windows. // Window manager hints for fullscreen windows.
// Not used right now (the code is written, but is not 64bit-correct), but could be useful for older WMs which // Not used right now (the code is written, but is not 64bit-correct), but could be useful for older WMs which
// are not ICCM compliant, but may support MOTIF hints. // are not ICCM compliant, but may support MOTIF hints.
@ -116,6 +111,13 @@ namespace OpenTK.Platform.X11
bool _decorations_hidden = false; bool _decorations_hidden = false;
// Store previous border and bounds
// when switching from WindowState.Normal
// to a different state. When switching
// back, reset window to these.s
WindowBorder _previous_window_border;
Size _previous_window_size;
MouseCursor cursor = MouseCursor.Default; MouseCursor cursor = MouseCursor.Default;
IntPtr cursorHandle; IntPtr cursorHandle;
bool cursor_visible = true; bool cursor_visible = true;
@ -124,14 +126,14 @@ namespace OpenTK.Platform.X11
// Keyboard input // Keyboard input
readonly byte[] ascii = new byte[16]; readonly byte[] ascii = new byte[16];
readonly char[] chars = new char[16]; readonly char[] chars = new char[16];
readonly KeyPressEventArgs KPEventArgs = new KeyPressEventArgs('\0');
readonly KeyboardKeyEventArgs KeyDownEventArgs = new KeyboardKeyEventArgs();
readonly KeyboardKeyEventArgs KeyUpEventArgs = new KeyboardKeyEventArgs();
readonly IntPtr EmptyCursor; readonly IntPtr EmptyCursor;
public static bool MouseWarpActive = false; public static bool MouseWarpActive = false;
readonly bool xi2_supported;
readonly int xi2_opcode;
#endregion #endregion
#region Constructors #region Constructors
@ -224,15 +226,26 @@ namespace OpenTK.Platform.X11
e.ConfigureEvent.height = height; e.ConfigureEvent.height = height;
RefreshWindowBounds(ref e); RefreshWindowBounds(ref e);
driver = new X11Input(window);
keyboard = driver.Keyboard[0];
mouse = driver.Mouse[0];
EmptyCursor = CreateEmptyCursor(window); EmptyCursor = CreateEmptyCursor(window);
Debug.WriteLine(String.Format("X11GLNative window created successfully (id: {0}).", Handle)); Debug.WriteLine(String.Format("X11GLNative window created successfully (id: {0}).", Handle));
Debug.Unindent(); Debug.Unindent();
// Request that auto-repeat is only set on devices that support it physically.
// This typically means that it's turned off for keyboards (which is what we want).
// We prefer this method over XAutoRepeatOff/On, because the latter needs to
// be reset before the program exits.
bool supported;
Functions.XkbSetDetectableAutoRepeat(window.Display, true, out supported);
// The XInput2 extension makes keyboard and mouse handling much easier.
// Check whether it is available.
xi2_supported = XI2Mouse.IsSupported(window.Display);
if (xi2_supported)
{
xi2_opcode = XI2Mouse.XIOpCode;
}
exists = true; exists = true;
} }
@ -733,7 +746,7 @@ namespace OpenTK.Platform.X11
if (Location != new_location) if (Location != new_location)
{ {
bounds.Location = new_location; bounds.Location = new_location;
Move(this, EventArgs.Empty); OnMove(EventArgs.Empty);
} }
// Note: width and height denote the internal (client) size. // Note: width and height denote the internal (client) size.
@ -744,9 +757,15 @@ namespace OpenTK.Platform.X11
if (Bounds.Size != new_size) if (Bounds.Size != new_size)
{ {
bounds.Size = new_size; bounds.Size = new_size;
client_rectangle.Size = new Size(e.ConfigureEvent.width, e.ConfigureEvent.height);
Resize(this, EventArgs.Empty); // X11 sets the client width/height to 0
// when the window is minimized. Many apps
// do not expect this and crash, so clamp
// minimum width/height to 1 instead.
client_rectangle.Size = new Size(
Math.Max(e.ConfigureEvent.width, 1),
Math.Max(e.ConfigureEvent.height, 1));
OnResize(EventArgs.Empty);
} }
//Debug.Print("[X11] Window bounds changed: {0}", bounds); //Debug.Print("[X11] Window bounds changed: {0}", bounds);
@ -768,25 +787,15 @@ namespace OpenTK.Platform.X11
return cursor; return cursor;
} }
static void SetMouseClamped(MouseDevice mouse, int x, int y,
int left, int top, int width, int height)
{
// Clamp mouse to the specified rectangle.
x = Math.Max(x, left);
x = Math.Min(x, width);
y = Math.Max(y, top);
y = Math.Min(y, height);
mouse.Position = new Point(x, y);
}
#endregion #endregion
#region INativeWindow Members #region INativeWindow Members
#region ProcessEvents #region ProcessEvents
public void ProcessEvents() public override void ProcessEvents()
{ {
base.ProcessEvents();
// Process all pending events // Process all pending events
while (Exists && window != null) while (Exists && window != null)
{ {
@ -805,7 +814,7 @@ namespace OpenTK.Platform.X11
bool previous_visible = visible; bool previous_visible = visible;
visible = true; visible = true;
if (visible != previous_visible) if (visible != previous_visible)
VisibleChanged(this, EventArgs.Empty); OnVisibleChanged(EventArgs.Empty);
} }
return; return;
@ -814,7 +823,7 @@ namespace OpenTK.Platform.X11
bool previous_visible = visible; bool previous_visible = visible;
visible = false; visible = false;
if (visible != previous_visible) if (visible != previous_visible)
VisibleChanged(this, EventArgs.Empty); OnVisibleChanged(EventArgs.Empty);
} }
break; break;
@ -827,7 +836,7 @@ namespace OpenTK.Platform.X11
{ {
Debug.WriteLine("Exit message received."); Debug.WriteLine("Exit message received.");
CancelEventArgs ce = new CancelEventArgs(); CancelEventArgs ce = new CancelEventArgs();
Closing(this, ce); OnClosing(ce);
if (!ce.Cancel) if (!ce.Cancel)
{ {
@ -848,7 +857,7 @@ namespace OpenTK.Platform.X11
Debug.WriteLine("Window destroyed"); Debug.WriteLine("Window destroyed");
exists = false; exists = false;
Closed(this, EventArgs.Empty); OnClosed(EventArgs.Empty);
return; return;
@ -860,26 +869,18 @@ namespace OpenTK.Platform.X11
case XEventName.KeyRelease: case XEventName.KeyRelease:
bool pressed = e.type == XEventName.KeyPress; bool pressed = e.type == XEventName.KeyPress;
Key key; Key key;
if (driver.TranslateKey(ref e.KeyEvent, out key)) if (X11KeyMap.TranslateKey(ref e.KeyEvent, out key))
{ {
// Update legacy GameWindow.Keyboard API:
keyboard.SetKey(key, (uint)e.KeyEvent.keycode, pressed);
if (pressed) if (pressed)
{ {
// Raise KeyDown event // Raise KeyDown event
KeyDownEventArgs.Key = key; bool is_repeat = KeyboardState[key];
KeyDownEventArgs.ScanCode = (uint)e.KeyEvent.keycode; OnKeyDown(key, is_repeat);
KeyDownEventArgs.Modifiers = keyboard.GetModifiers();
KeyDown(this, KeyDownEventArgs);
} }
else else
{ {
// Raise KeyUp event // Raise KeyUp event
KeyUpEventArgs.Key = key; OnKeyUp(key);
KeyUpEventArgs.ScanCode = (uint)e.KeyEvent.keycode;
KeyUpEventArgs.Modifiers = keyboard.GetModifiers();
KeyUp(this, KeyUpEventArgs);
} }
if (pressed) if (pressed)
@ -895,8 +896,7 @@ namespace OpenTK.Platform.X11
{ {
if (!Char.IsControl(chars[i])) if (!Char.IsControl(chars[i]))
{ {
KPEventArgs.KeyChar = chars[i]; OnKeyPress(chars[i]);
KeyPress(this, KPEventArgs);
} }
} }
} }
@ -929,10 +929,9 @@ namespace OpenTK.Platform.X11
} }
else if (!CursorVisible) else if (!CursorVisible)
{ {
SetMouseClamped(mouse, OnMouseMove(
mouse.X + x - mouse_rel_x, MathHelper.Clamp(MouseState.X + x - mouse_rel_x, 0, Width),
mouse.Y + y - mouse_rel_y, MathHelper.Clamp(MouseState.Y + y - mouse_rel_y, 0, Height));
0, 0, Width, Height);
mouse_rel_x = x; mouse_rel_x = x;
mouse_rel_y = y; mouse_rel_y = y;
@ -942,16 +941,42 @@ namespace OpenTK.Platform.X11
} }
else else
{ {
SetMouseClamped(mouse, x, y, 0, 0, Width, Height); OnMouseMove(
MathHelper.Clamp(x, 0, Width),
MathHelper.Clamp(y, 0, Height));
mouse_rel_x = x; mouse_rel_x = x;
mouse_rel_y = y; mouse_rel_y = y;
} }
break; break;
} }
case XEventName.ButtonPress: case XEventName.ButtonPress:
{
int dx, dy;
MouseButton button = X11KeyMap.TranslateButton(e.ButtonEvent.button, out dx, out dy);
if (button != MouseButton.LastButton)
{
OnMouseDown(button);
}
else if (dx != 0 || dy != 0)
{
OnMouseWheel(dx, dy);
}
}
break;
case XEventName.ButtonRelease: case XEventName.ButtonRelease:
driver.ProcessEvent(ref e); {
int dx, dy;
MouseButton button = X11KeyMap.TranslateButton(e.ButtonEvent.button, out dx, out dy);
if (button != MouseButton.LastButton)
{
OnMouseUp(button);
}
}
break; break;
case XEventName.FocusIn: case XEventName.FocusIn:
@ -959,7 +984,7 @@ namespace OpenTK.Platform.X11
bool previous_focus = has_focus; bool previous_focus = has_focus;
has_focus = true; has_focus = true;
if (has_focus != previous_focus) if (has_focus != previous_focus)
FocusedChanged(this, EventArgs.Empty); OnFocusedChanged(EventArgs.Empty);
} }
break; break;
@ -968,19 +993,19 @@ namespace OpenTK.Platform.X11
bool previous_focus = has_focus; bool previous_focus = has_focus;
has_focus = false; has_focus = false;
if (has_focus != previous_focus) if (has_focus != previous_focus)
FocusedChanged(this, EventArgs.Empty); OnFocusedChanged(EventArgs.Empty);
} }
break; break;
case XEventName.LeaveNotify: case XEventName.LeaveNotify:
if (CursorVisible) if (CursorVisible)
{ {
MouseLeave(this, EventArgs.Empty); OnMouseLeave(EventArgs.Empty);
} }
break; break;
case XEventName.EnterNotify: case XEventName.EnterNotify:
MouseEnter(this, EventArgs.Empty); OnMouseEnter(EventArgs.Empty);
break; break;
case XEventName.MappingNotify: case XEventName.MappingNotify:
@ -995,7 +1020,7 @@ namespace OpenTK.Platform.X11
case XEventName.PropertyNotify: case XEventName.PropertyNotify:
if (e.PropertyEvent.atom == _atom_net_wm_state) if (e.PropertyEvent.atom == _atom_net_wm_state)
{ {
WindowStateChanged(this, EventArgs.Empty); OnWindowStateChanged(EventArgs.Empty);
} }
//if (e.PropertyEvent.atom == _atom_net_frame_extents) //if (e.PropertyEvent.atom == _atom_net_frame_extents)
@ -1015,7 +1040,7 @@ namespace OpenTK.Platform.X11
#region Bounds #region Bounds
public Rectangle Bounds public override Rectangle Bounds
{ {
get get
{ {
@ -1061,50 +1086,18 @@ namespace OpenTK.Platform.X11
#endregion #endregion
#region Location #region ClientSize
public Point Location public override Size ClientSize
{
get { return Bounds.Location; }
set
{
Bounds = new Rectangle(value, Bounds.Size);
}
}
#endregion
#region Size
public Size Size
{
get { return Bounds.Size; }
set
{
Bounds = new Rectangle(Bounds.Location, value);
}
}
#endregion
#region ClientRectangle
public Rectangle ClientRectangle
{ {
get get
{ {
if (client_rectangle.Width == 0) return client_rectangle.Size;
client_rectangle.Width = 1;
if (client_rectangle.Height == 0)
client_rectangle.Height = 1;
return client_rectangle;
} }
set set
{ {
using (new XLock(window.Display)) using (new XLock(window.Display))
{ {
Functions.XMoveWindow(window.Display, window.Handle,
value.X, value.Y);
Functions.XResizeWindow(window.Display, window.Handle, Functions.XResizeWindow(window.Display, window.Handle,
value.Width, value.Height); value.Width, value.Height);
} }
@ -1114,65 +1107,9 @@ namespace OpenTK.Platform.X11
#endregion #endregion
#region ClientSize
public Size ClientSize
{
get
{
return ClientRectangle.Size;
}
set
{
ClientRectangle = new Rectangle(Point.Empty, value);
}
}
#endregion
#region Width
public int Width
{
get { return ClientSize.Width; }
set { ClientSize = new Size(value, Height); }
}
#endregion
#region Height
public int Height
{
get { return ClientSize.Height; }
set { ClientSize = new Size(Width, value); }
}
#endregion
#region X
public int X
{
get { return Location.X; }
set { Location = new Point(value, Y); }
}
#endregion
#region Y
public int Y
{
get { return Location.Y; }
set { Location = new Point(X, value); }
}
#endregion
#region Icon #region Icon
public Icon Icon public override Icon Icon
{ {
get get
{ {
@ -1238,7 +1175,7 @@ namespace OpenTK.Platform.X11
} }
icon = value; icon = value;
IconChanged(this, EventArgs.Empty); OnIconChanged(EventArgs.Empty);
} }
} }
@ -1246,7 +1183,7 @@ namespace OpenTK.Platform.X11
#region Focused #region Focused
public bool Focused public override bool Focused
{ {
get get
{ {
@ -1258,7 +1195,7 @@ namespace OpenTK.Platform.X11
#region WindowState #region WindowState
public OpenTK.WindowState WindowState public override OpenTK.WindowState WindowState
{ {
get get
{ {
@ -1319,44 +1256,86 @@ namespace OpenTK.Platform.X11
{ {
OpenTK.WindowState current_state = this.WindowState; OpenTK.WindowState current_state = this.WindowState;
// When switching away from normal state, store
// the "normal" border and size. These will be used
// for restoring to normal state.
if (current_state == OpenTK.WindowState.Normal)
{
_previous_window_border = WindowBorder;
_previous_window_size = ClientSize;
}
if (current_state == value) if (current_state == value)
return; return;
Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.Handle.ToString(), Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.Handle.ToString(),
current_state.ToString(), value.ToString()); current_state.ToString(), value.ToString());
// When minimizing the window, call XIconifyWindow and bail out.
// For other states, we first need to restore the window, set the
// new state and reset the window border and bounds.
if (value != OpenTK.WindowState.Minimized)
{
// Some WMs cannot switch between specific states directly,
// Switch back to a regular window first.
if (WindowBorder == WindowBorder.Fixed)
{
ChangeWindowBorder(WindowBorder.Resizable);
}
ResetWindowState(current_state);
}
// Change to the desired WindowState.
// Note that OnWindowStateChanged is called inside
// ProcessEvents.
ChangeWindowState(value);
ProcessEvents();
}
}
void ResetWindowState(OpenTK.WindowState current_state)
{
if (current_state != OpenTK.WindowState.Normal)
{
using (new XLock(window.Display)) using (new XLock(window.Display))
{ {
// Reset the current window state switch (current_state)
if (current_state == OpenTK.WindowState.Minimized) {
case OpenTK.WindowState.Minimized:
Functions.XMapWindow(window.Display, window.Handle); Functions.XMapWindow(window.Display, window.Handle);
else if (current_state == OpenTK.WindowState.Fullscreen) break;
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove,
case OpenTK.WindowState.Fullscreen:
Functions.SendNetWMMessage(window,
_atom_net_wm_state,
_atom_remove,
_atom_net_wm_state_fullscreen, _atom_net_wm_state_fullscreen,
IntPtr.Zero); IntPtr.Zero);
else if (current_state == OpenTK.WindowState.Maximized) break;
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle,
case OpenTK.WindowState.Maximized:
Functions.SendNetWMMessage(window,
_atom_net_wm_state,
_atom_toggle,
_atom_net_wm_state_maximized_horizontal, _atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical); _atom_net_wm_state_maximized_vertical);
break;
Functions.XSync(window.Display, false);
} }
// We can't resize the window if its border is fixed, so make it resizable first. }
bool temporary_resizable = false; }
WindowBorder previous_state = WindowBorder; }
if (WindowBorder != WindowBorder.Resizable)
void ChangeWindowState(OpenTK.WindowState value)
{ {
temporary_resizable = true;
WindowBorder = WindowBorder.Resizable;
}
using (new XLock(window.Display)) using (new XLock(window.Display))
{ {
switch (value) switch (value)
{ {
case OpenTK.WindowState.Normal: case OpenTK.WindowState.Normal:
Functions.XRaiseWindow(window.Display, window.Handle); Functions.XRaiseWindow(window.Display, window.Handle);
ChangeWindowBorder(_previous_window_border,
_previous_window_size.Width, _previous_window_size.Height);
break; break;
case OpenTK.WindowState.Maximized: case OpenTK.WindowState.Maximized:
@ -1364,54 +1343,64 @@ namespace OpenTK.Platform.X11
_atom_net_wm_state_maximized_horizontal, _atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical); _atom_net_wm_state_maximized_vertical);
Functions.XRaiseWindow(window.Display, window.Handle); Functions.XRaiseWindow(window.Display, window.Handle);
break; break;
case OpenTK.WindowState.Minimized: case OpenTK.WindowState.Minimized:
// Todo: multiscreen support
Functions.XIconifyWindow(window.Display, window.Handle, window.Screen); Functions.XIconifyWindow(window.Display, window.Handle, window.Screen);
break; break;
case OpenTK.WindowState.Fullscreen: case OpenTK.WindowState.Fullscreen:
//_previous_window_border = this.WindowBorder;
//this.WindowBorder = WindowBorder.Hidden;
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add, Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_net_wm_state_fullscreen, IntPtr.Zero); _atom_net_wm_state_fullscreen, IntPtr.Zero);
Functions.XRaiseWindow(window.Display, window.Handle); Functions.XRaiseWindow(window.Display, window.Handle);
break; break;
} }
} }
if (temporary_resizable)
WindowBorder = previous_state;
ProcessEvents();
}
} }
#endregion #endregion
#region WindowBorder #region WindowBorder
public OpenTK.WindowBorder WindowBorder public override OpenTK.WindowBorder WindowBorder
{ {
get get
{ {
if (IsWindowBorderHidden) if (IsWindowBorderHidden || WindowState == OpenTK.WindowState.Fullscreen)
return WindowBorder.Hidden; return WindowBorder.Hidden;
else if (!IsWindowBorderResizable)
if (IsWindowBorderResizable)
return WindowBorder.Resizable;
else
return WindowBorder.Fixed; return WindowBorder.Fixed;
else if (WindowState == OpenTK.WindowState.Maximized)
return _previous_window_border;
else
return WindowBorder.Resizable;
} }
set set
{ {
if (WindowBorder == value) if (WindowBorder == value)
return; return;
// We cannot change the border of a fullscreen window.
// Record the new value and set it on the next WindowState
// change.
if (WindowState == OpenTK.WindowState.Fullscreen)
{
_previous_window_border = value;
return;
}
ChangeWindowBorder(value);
OnWindowBorderChanged(EventArgs.Empty);
}
}
void ChangeWindowBorder(WindowBorder value)
{
ChangeWindowBorder(value, Width, Height);
}
void ChangeWindowBorder(WindowBorder value, int width, int height)
{
if (WindowBorder == WindowBorder.Hidden) if (WindowBorder == WindowBorder.Hidden)
EnableWindowDecorations(); EnableWindowDecorations();
@ -1419,53 +1408,30 @@ namespace OpenTK.Platform.X11
{ {
case WindowBorder.Fixed: case WindowBorder.Fixed:
Debug.Print("Making WindowBorder fixed."); Debug.Print("Making WindowBorder fixed.");
SetWindowMinMax((short)Width, (short)Height, (short)Width, (short)Height); SetWindowMinMax((short)width, (short)height, (short)width, (short)height);
break; break;
case WindowBorder.Resizable: case WindowBorder.Resizable:
Debug.Print("Making WindowBorder resizable."); Debug.Print("Making WindowBorder resizable.");
SetWindowMinMax(_min_width, _min_height, -1, -1); SetWindowMinMax(_min_width, _min_height, -1, -1);
break; break;
case WindowBorder.Hidden: case WindowBorder.Hidden:
Debug.Print("Making WindowBorder hidden."); Debug.Print("Making WindowBorder hidden.");
// Make the hidden border resizable, otherwise
// we won't be able to maximize the window or
// enter fullscreen mode.
SetWindowMinMax(_min_width, _min_height, -1, -1);
DisableWindowDecorations(); DisableWindowDecorations();
break; break;
} }
WindowBorderChanged(this, EventArgs.Empty); ProcessEvents();
} }
}
#endregion
#region Events
public event EventHandler<EventArgs> Move = delegate { };
public event EventHandler<EventArgs> Resize = delegate { };
public event EventHandler<System.ComponentModel.CancelEventArgs> Closing = delegate { };
public event EventHandler<EventArgs> Closed = delegate { };
public event EventHandler<EventArgs> Disposed = delegate { };
public event EventHandler<EventArgs> IconChanged = delegate { };
public event EventHandler<EventArgs> TitleChanged = delegate { };
public event EventHandler<EventArgs> VisibleChanged = delegate { };
public event EventHandler<EventArgs> FocusedChanged = delegate { };
public event EventHandler<EventArgs> WindowBorderChanged = delegate { };
public event EventHandler<EventArgs> WindowStateChanged = delegate { };
public event EventHandler<KeyboardKeyEventArgs> KeyDown = delegate { };
public event EventHandler<KeyPressEventArgs> KeyPress = delegate { };
public event EventHandler<KeyboardKeyEventArgs> KeyUp = delegate { };
public event EventHandler<EventArgs> MouseEnter = delegate { };
public event EventHandler<EventArgs> MouseLeave = delegate { };
#endregion #endregion
#region Cursor #region Cursor
public MouseCursor Cursor public override MouseCursor Cursor
{ {
get get
{ {
@ -1505,7 +1471,7 @@ namespace OpenTK.Platform.X11
#region CursorVisible #region CursorVisible
public bool CursorVisible public override bool CursorVisible
{ {
get { return cursor_visible; } get { return cursor_visible; }
set set
@ -1535,24 +1501,12 @@ namespace OpenTK.Platform.X11
#region --- INativeGLWindow Members --- #region --- INativeGLWindow Members ---
#region public IInputDriver InputDriver
public IInputDriver InputDriver
{
get
{
return driver;
}
}
#endregion
#region public bool Exists #region public bool Exists
/// <summary> /// <summary>
/// Returns true if a render window/context exists. /// Returns true if a render window/context exists.
/// </summary> /// </summary>
public bool Exists public override bool Exists
{ {
get { return exists; } get { return exists; }
} }
@ -1586,7 +1540,7 @@ namespace OpenTK.Platform.X11
/// TODO: Use atoms for this property. /// TODO: Use atoms for this property.
/// Gets or sets the GameWindow title. /// Gets or sets the GameWindow title.
/// </summary> /// </summary>
public string Title public override string Title
{ {
get get
{ {
@ -1610,7 +1564,7 @@ namespace OpenTK.Platform.X11
} }
} }
TitleChanged(this, EventArgs.Empty); OnTitleChanged(EventArgs.Empty);
} }
} }
@ -1618,7 +1572,7 @@ namespace OpenTK.Platform.X11
#region public bool Visible #region public bool Visible
public bool Visible public override bool Visible
{ {
get get
{ {
@ -1647,14 +1601,14 @@ namespace OpenTK.Platform.X11
#region public IWindowInfo WindowInfo #region public IWindowInfo WindowInfo
public IWindowInfo WindowInfo public override IWindowInfo WindowInfo
{ {
get { return window; } get { return window; }
} }
#endregion #endregion
public void Close() { Exit(); } public override void Close() { Exit(); }
#region public void Exit() #region public void Exit()
@ -1691,7 +1645,7 @@ namespace OpenTK.Platform.X11
#region PointToClient #region PointToClient
public Point PointToClient(Point point) public override Point PointToClient(Point point)
{ {
int ox, oy; int ox, oy;
IntPtr child; IntPtr child;
@ -1711,7 +1665,7 @@ namespace OpenTK.Platform.X11
#region PointToScreen #region PointToScreen
public Point PointToScreen(Point point) public override Point PointToScreen(Point point)
{ {
int ox, oy; int ox, oy;
IntPtr child; IntPtr child;
@ -1733,13 +1687,7 @@ namespace OpenTK.Platform.X11
#region IDisposable Members #region IDisposable Members
public void Dispose() protected override void Dispose(bool manuallyCalled)
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool manuallyCalled)
{ {
if (!disposed) if (!disposed)
{ {
@ -1775,11 +1723,6 @@ namespace OpenTK.Platform.X11
} }
} }
~X11GLNative()
{
this.Dispose(false);
}
#endregion #endregion
} }
} }

View file

@ -1,235 +0,0 @@
#region --- License ---
/* Copyright (c) 2006, 2007 Stefanos Apostolopoulos
* See license.txt for license info
*/
#endregion
using System;
using System.Collections.Generic;
#if !MINIMAL
using System.Drawing;
#endif
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using OpenTK.Input;
namespace OpenTK.Platform.X11
{
/// \internal
/// <summary>
/// Drives the InputDriver on X11.
/// This class supports OpenTK, and is not intended for users of OpenTK.
/// </summary>
internal sealed class X11Input : IInputDriver
{
KeyboardDevice keyboard = new KeyboardDevice();
MouseDevice mouse = new MouseDevice();
List<KeyboardDevice> dummy_keyboard_list = new List<KeyboardDevice>(1);
List<MouseDevice> dummy_mice_list = new List<MouseDevice>(1);
int firstKeyCode, lastKeyCode; // The smallest and largest KeyCode supported by the X server.
int keysyms_per_keycode; // The number of KeySyms for each KeyCode.
IntPtr[] keysyms;
//bool disposed;
#region --- Constructors ---
/// <summary>
/// Constructs a new X11Input driver. Creates a hidden InputOnly window, child to
/// the main application window, which selects input events and routes them to
/// the device specific drivers (Keyboard, Mouse, Hid).
/// </summary>
/// <param name="attach">The window which the InputDriver will attach itself on.</param>
public X11Input(IWindowInfo attach)
{
Debug.WriteLine("Initalizing X11 input driver.");
Debug.Indent();
if (attach == null)
throw new ArgumentException("A valid parent window must be defined, in order to create an X11Input driver.");
//window = new X11WindowInfo(attach);
X11WindowInfo window = (X11WindowInfo)attach;
// Init mouse
mouse.Description = "Default X11 mouse";
mouse.DeviceID = IntPtr.Zero;
mouse.NumberOfButtons = 5;
mouse.NumberOfWheels = 1;
dummy_mice_list.Add(mouse);
using (new XLock(window.Display))
{
// Init keyboard
API.DisplayKeycodes(window.Display, ref firstKeyCode, ref lastKeyCode);
Debug.Print("First keycode: {0}, last {1}", firstKeyCode, lastKeyCode);
IntPtr keysym_ptr = API.GetKeyboardMapping(window.Display, (byte)firstKeyCode,
lastKeyCode - firstKeyCode + 1, ref keysyms_per_keycode);
Debug.Print("{0} keysyms per keycode.", keysyms_per_keycode);
keysyms = new IntPtr[(lastKeyCode - firstKeyCode + 1) * keysyms_per_keycode];
Marshal.PtrToStructure(keysym_ptr, keysyms);
API.Free(keysym_ptr);
keyboard.Description = "Default X11 keyboard";
keyboard.NumberOfKeys = lastKeyCode - firstKeyCode + 1;
keyboard.DeviceID = IntPtr.Zero;
dummy_keyboard_list.Add(keyboard);
// Request that auto-repeat is only set on devices that support it physically.
// This typically means that it's turned off for keyboards (which is what we want).
// We prefer this method over XAutoRepeatOff/On, because the latter needs to
// be reset before the program exits.
bool supported;
Functions.XkbSetDetectableAutoRepeat(window.Display, true, out supported);
}
Debug.Unindent();
}
#endregion
#region TranslateKey
internal bool TranslateKey(ref XKeyEvent e, out Key key)
{
XKey keysym = (XKey)API.LookupKeysym(ref e, 0);
XKey keysym2 = (XKey)API.LookupKeysym(ref e, 1);
key = X11KeyMap.GetKey(keysym);
if (key == Key.Unknown)
{
key = X11KeyMap.GetKey(keysym2);
}
if (key == Key.Unknown)
{
Debug.Print("KeyCode {0} (Keysym: {1}, {2}) not mapped.", e.keycode, (XKey)keysym, (XKey)keysym2);
}
return key != Key.Unknown;
}
#endregion
#region internal void ProcessEvent(ref XEvent e)
internal void ProcessEvent(ref XEvent e)
{
switch (e.type)
{
case XEventName.ButtonPress:
if (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = true;
else if (e.ButtonEvent.button == 2) mouse[OpenTK.Input.MouseButton.Middle] = true;
else if (e.ButtonEvent.button == 3) mouse[OpenTK.Input.MouseButton.Right] = true;
else if (e.ButtonEvent.button == 4) mouse.Wheel++;
else if (e.ButtonEvent.button == 5) mouse.Wheel--;
else if (e.ButtonEvent.button == 6) mouse[OpenTK.Input.MouseButton.Button1] = true;
else if (e.ButtonEvent.button == 7) mouse[OpenTK.Input.MouseButton.Button2] = true;
else if (e.ButtonEvent.button == 8) mouse[OpenTK.Input.MouseButton.Button3] = true;
else if (e.ButtonEvent.button == 9) mouse[OpenTK.Input.MouseButton.Button4] = true;
else if (e.ButtonEvent.button == 10) mouse[OpenTK.Input.MouseButton.Button5] = true;
else if (e.ButtonEvent.button == 11) mouse[OpenTK.Input.MouseButton.Button6] = true;
else if (e.ButtonEvent.button == 12) mouse[OpenTK.Input.MouseButton.Button7] = true;
else if (e.ButtonEvent.button == 13) mouse[OpenTK.Input.MouseButton.Button8] = true;
else if (e.ButtonEvent.button == 14) mouse[OpenTK.Input.MouseButton.Button9] = true;
//if ((e.state & (int)X11.MouseMask.Button4Mask) != 0) m.Wheel++;
//if ((e.state & (int)X11.MouseMask.Button5Mask) != 0) m.Wheel--;
//Debug.Print("Button pressed: {0}", e.ButtonEvent.button);
break;
case XEventName.ButtonRelease:
if (e.ButtonEvent.button == 1) mouse[OpenTK.Input.MouseButton.Left] = false;
else if (e.ButtonEvent.button == 2) mouse[OpenTK.Input.MouseButton.Middle] = false;
else if (e.ButtonEvent.button == 3) mouse[OpenTK.Input.MouseButton.Right] = false;
else if (e.ButtonEvent.button == 6) mouse[OpenTK.Input.MouseButton.Button1] = false;
else if (e.ButtonEvent.button == 7) mouse[OpenTK.Input.MouseButton.Button2] = false;
else if (e.ButtonEvent.button == 8) mouse[OpenTK.Input.MouseButton.Button3] = false;
else if (e.ButtonEvent.button == 9) mouse[OpenTK.Input.MouseButton.Button4] = false;
else if (e.ButtonEvent.button == 10) mouse[OpenTK.Input.MouseButton.Button5] = false;
else if (e.ButtonEvent.button == 11) mouse[OpenTK.Input.MouseButton.Button6] = false;
else if (e.ButtonEvent.button == 12) mouse[OpenTK.Input.MouseButton.Button7] = false;
else if (e.ButtonEvent.button == 13) mouse[OpenTK.Input.MouseButton.Button8] = false;
else if (e.ButtonEvent.button == 14) mouse[OpenTK.Input.MouseButton.Button9] = false;
break;
case XEventName.MotionNotify:
mouse.Position = new Point(e.MotionEvent.x, e.MotionEvent.y);
break;
}
}
#endregion
#region --- IInputDriver Members ---
#region public IList<Keyboard> Keyboard
public IList<KeyboardDevice> Keyboard
{
get { return dummy_keyboard_list; }//return keyboardDriver.Keyboard;
}
#endregion
#region public IList<Mouse> Mouse
public IList<MouseDevice> Mouse
{
get { return (IList<MouseDevice>)dummy_mice_list; } //return mouseDriver.Mouse;
}
#endregion
public IList<JoystickDevice> Joysticks
{
get { throw new NotImplementedException(); }
}
#endregion
#region public void Poll()
/// <summary>
/// Polls and updates state of all keyboard, mouse and joystick devices.
/// </summary>
public void Poll()
{
}
#endregion
#region --- IDisposable Members ---
public void Dispose()
{
//this.Dispose(true);
//GC.SuppressFinalize(this);
}
//private void Dispose(bool manual)
//{
// if (!disposed)
// {
// //disposing = true;
// if (pollingThread != null && pollingThread.IsAlive)
// pollingThread.Abort();
// if (manual)
// {
// }
// disposed = true;
// }
//}
//~X11Input()
//{
// this.Dispose(false);
//}
#endregion
}
}

View file

@ -370,5 +370,47 @@ namespace OpenTK.Platform.X11
return Key.Unknown; return Key.Unknown;
} }
} }
internal static bool TranslateKey(ref XKeyEvent e, out Key key)
{
XKey keysym = (XKey)API.LookupKeysym(ref e, 0);
XKey keysym2 = (XKey)API.LookupKeysym(ref e, 1);
key = X11KeyMap.GetKey(keysym);
if (key == Key.Unknown)
{
key = X11KeyMap.GetKey(keysym2);
}
if (key == Key.Unknown)
{
Debug.Print("KeyCode {0} (Keysym: {1}, {2}) not mapped.", e.keycode, (XKey)keysym, (XKey)keysym2);
}
return key != Key.Unknown;
}
internal static MouseButton TranslateButton(int button, out int wheelx, out int wheely)
{
wheelx = 0;
wheely = 0;
switch (button)
{
case 1: return MouseButton.Left;
case 2: return MouseButton.Middle;
case 3: return MouseButton.Right;
case 4: wheely = +1; return MouseButton.LastButton;
case 5: wheely = -1; return MouseButton.LastButton;
case 6: wheelx = +1; return MouseButton.LastButton;
case 7: wheelx = -1; return MouseButton.LastButton;
case 8: return MouseButton.Button1;
case 9: return MouseButton.Button2;
case 10: return MouseButton.Button3;
case 11: return MouseButton.Button4;
case 12: return MouseButton.Button5;
case 13: return MouseButton.Button6;
case 14: return MouseButton.Button7;
default: return MouseButton.LastButton;
}
}
} }
} }

View file

@ -40,7 +40,8 @@ namespace OpenTK.Platform.X11
List<MouseState> mice = new List<MouseState>(); List<MouseState> mice = new List<MouseState>();
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids
internal readonly X11WindowInfo window; internal readonly X11WindowInfo window;
static int XIOpCode; internal static int XIOpCode { get; private set; }
static bool supported;
static readonly Functions.EventPredicate PredicateImpl = IsEventValid; static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl); readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
@ -204,8 +205,8 @@ namespace OpenTK.Platform.X11
case 1: state.EnableBit((int)MouseButton.Left); break; case 1: state.EnableBit((int)MouseButton.Left); break;
case 2: state.EnableBit((int)MouseButton.Middle); break; case 2: state.EnableBit((int)MouseButton.Middle); break;
case 3: state.EnableBit((int)MouseButton.Right); break; case 3: state.EnableBit((int)MouseButton.Right); break;
case 4: state.WheelPrecise++; break; case 4: state.SetScrollRelative(0, 1); break;
case 5: state.WheelPrecise--; break; case 5: state.SetScrollRelative(0, -1); break;
case 6: state.EnableBit((int)MouseButton.Button1); break; case 6: state.EnableBit((int)MouseButton.Button1); break;
case 7: state.EnableBit((int)MouseButton.Button2); break; case 7: state.EnableBit((int)MouseButton.Button2); break;
case 8: state.EnableBit((int)MouseButton.Button3); break; case 8: state.EnableBit((int)MouseButton.Button3); break;