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

@ -549,7 +549,7 @@
<None Include="Data\Audio\the_ring_that_fell.wav">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Data\Textures\cursor.png">
<None Include="Data\Textures\cursor.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<EmbeddedResource Include="OpenGL\1.x\OpenGLDiagnostics.rtf" />
@ -572,6 +572,7 @@
<Link>Dependencies\x64\libSDL2.dylib</Link>
</None>
<Compile Include="OpenTK\Test\ExternalContext.cs" />
<Compile Include="OpenTK\Test\PointToClient.cs" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">

View file

@ -26,6 +26,28 @@ namespace Examples.Tests
bool mouse_in_window = false;
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
Stopwatch watch = new Stopwatch();
double update_time, render_time;
@ -42,8 +64,6 @@ namespace Examples.Tests
double variable_refresh_timestep_pos = -1;
double fixed_update_timestep_pos = -1;
KeyModifiers modifiers;
public GameWindowStates()
: base(800, 600, GraphicsMode.Default)
{
@ -52,16 +72,26 @@ namespace Examples.Tests
KeyDown += KeyDownHandler;
KeyUp += KeyUpHandler;
KeyPress += KeyPressHandler;
Keyboard.KeyDown += KeyboardDeviceDownHandler;
Keyboard.KeyUp += KeyboardDeviceUpHandler;
MouseEnter += delegate { mouse_in_window = true; };
MouseLeave += delegate { mouse_in_window = false; };
Mouse.Move += MouseMoveHandler;
Mouse.ButtonDown += MouseButtonHandler;
Mouse.ButtonUp += MouseButtonHandler;
Mouse.Move += MouseDeviceMoveHandler;
Mouse.WheelChanged += MouseDeviceWheelHandler;
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)
TypedText.Remove(0, 1);
@ -108,27 +138,118 @@ namespace Examples.Tests
case Key.BracketRight: TargetUpdateFrequency++; break;
case Key.Comma: 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)
{
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)
{
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)
{
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)
{
return val > max ? max : val < min ? min : val;
@ -145,10 +266,23 @@ namespace Examples.Tests
return offset + gfx.MeasureString(str, TextFont).Width;
}
static void KeyboardStateToString(KeyboardState state, StringBuilder sb)
{
for (int key_index = 0; key_index < (int)Key.LastKey; key_index++)
{
Key k = (Key)key_index;
if (state[k])
{
sb.Append(k);
sb.Append(" ");
}
}
}
int DrawKeyboards(Graphics gfx, int line)
{
line++;
DrawString(gfx, String.Format("Keyboard ({0}):", modifiers), line++);
DrawString(gfx, "Keyboard:", line++);
for (int i = 0; i < 4; i++)
{
var state = OpenTK.Input.Keyboard.GetState(i);
@ -157,15 +291,7 @@ namespace Examples.Tests
StringBuilder sb = new StringBuilder();
sb.Append(i);
sb.Append(": ");
for (int key_index = 0; key_index < (int)Key.LastKey; key_index++)
{
Key k = (Key)key_index;
if (state[k])
{
sb.Append(k);
sb.Append(" ");
}
}
KeyboardStateToString(state, sb);
DrawString(gfx, sb.ToString(), line++);
}
}
@ -201,6 +327,112 @@ namespace Examples.Tests
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)
{
line++;
@ -236,6 +468,8 @@ namespace Examples.Tests
return line;
}
#endregion
protected override void OnUpdateFrame(FrameEventArgs e)
{
double clock_time = watch.Elapsed.TotalSeconds;
@ -267,7 +501,9 @@ namespace Examples.Tests
mouse_in_window ? "inside" : "outside",
CursorVisible ? "visible" : "hidden",
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
line++;
@ -350,6 +586,17 @@ namespace Examples.Tests
{
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.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;
internal protected IntPtr[] _EntryPointsInstance;
internal protected byte[] _EntryPointNamesInstance;
internal protected int[] _EntryPointNameOffsetsInstance;
internal IntPtr[] _EntryPointsInstance;
internal byte[] _EntryPointNamesInstance;
internal int[] _EntryPointNameOffsetsInstance;
/// <summary>
/// Retrieves an unmanaged function pointer to the specified function.

View file

@ -260,10 +260,26 @@ namespace OpenTK
/// </summary>
event EventHandler<EventArgs> MouseEnter;
//event EventHandler<MouseEventArgs> MouseMove;
//event EventHandler<MouseEventArgs> MouseWheel;
//event EventHandler<MouseEventArgs> MouseDown;
//event EventHandler<MouseEventArgs> MouseUp;
/// <summary>
/// Occurs whenever a <see cref="MouseButton"/> is clicked.
/// </summary>
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> MouseDoubleClick;

View file

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

View file

@ -46,8 +46,8 @@ namespace OpenTK.Input
#region Fields
Key key;
KeyModifiers mods;
uint scancode;
bool repeat;
KeyboardState state;
#endregion
@ -65,7 +65,6 @@ namespace OpenTK.Input
public KeyboardKeyEventArgs(KeyboardKeyEventArgs args)
{
Key = args.Key;
ScanCode = args.ScanCode;
}
#endregion
@ -87,8 +86,7 @@ namespace OpenTK.Input
[CLSCompliant(false)]
public uint ScanCode
{
get { return scancode; }
internal set { scancode = value; }
get { return (uint)Key; }
}
/// <summary>
@ -97,7 +95,7 @@ namespace OpenTK.Input
/// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value>
public bool Alt
{
get { return (mods & KeyModifiers.Alt) != 0; }
get { return state[Key.AltLeft] || state[Key.AltRight]; }
}
/// <summary>
@ -106,7 +104,7 @@ namespace OpenTK.Input
/// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value>
public bool Control
{
get { return (mods & KeyModifiers.Control) != 0; }
get { return state[Key.ControlLeft] || state[Key.ControlRight]; }
}
/// <summary>
@ -115,7 +113,7 @@ namespace OpenTK.Input
/// <value><c>true</c> if pressed; otherwise, <c>false</c>.</value>
public bool Shift
{
get { return (mods & KeyModifiers.Shift) != 0; }
get { return state[Key.ShiftLeft] || state[Key.ShiftRight]; }
}
/// <summary>
@ -125,8 +123,39 @@ namespace OpenTK.Input
/// <value>The modifiers.</value>
public KeyModifiers Modifiers
{
get { return mods; }
internal set { mods = value; }
get
{
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

View file

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

View file

@ -48,12 +48,8 @@ namespace OpenTK.Input
string description;
IntPtr id;
int numButtons, numWheels;
readonly bool[] button_state = new bool[Enum.GetValues(typeof(MouseButton)).Length];
float wheel, last_wheel;
Point pos = new Point(), last_pos = new Point();
MouseMoveEventArgs move_args = new MouseMoveEventArgs();
MouseButtonEventArgs button_args = new MouseButtonEventArgs();
MouseWheelEventArgs wheel_args = new MouseWheelEventArgs();
MouseState state;
#if COMPAT_REV1519
int wheel_last_accessed = 0;
Point pos_last_accessed = new Point();
@ -139,8 +135,7 @@ namespace OpenTK.Input
/// </summary>
public int Wheel
{
get { return (int)Math.Round(wheel, MidpointRounding.AwayFromZero); }
internal set { WheelPrecise = value; }
get { return state.Wheel; }
}
/// <summary>
@ -148,20 +143,7 @@ namespace OpenTK.Input
/// </summary>
public float WheelPrecise
{
get { return wheel; }
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;
}
get { return state.WheelPrecise; }
}
#endregion
@ -173,7 +155,7 @@ namespace OpenTK.Input
/// </summary>
public int X
{
get { return pos.X; }
get { return state.X; }
}
#endregion
@ -185,7 +167,7 @@ namespace OpenTK.Input
/// </summary>
public int Y
{
get { return pos.Y; }
get { return state.Y; }
}
#endregion
@ -201,21 +183,11 @@ namespace OpenTK.Input
{
get
{
return button_state[(int)button];
return state[button];
}
internal set
{
bool previous_state = button_state[(int)button];
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);
state[button] = value;
}
}
@ -225,26 +197,29 @@ namespace OpenTK.Input
#region --- Internal Members ---
#region internal Point Position
/// <summary>
/// Sets a System.Drawing.Point representing the absolute position of the pointer, in window pixel coordinates.
/// </summary>
internal Point Position
internal void HandleMouseDown(object sender, MouseButtonEventArgs e)
{
set
{
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;
}
state = e.Mouse;
ButtonDown(this, e);
}
#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
@ -309,8 +284,8 @@ namespace OpenTK.Input
{
get
{
int result = (int)Math.Round(wheel - wheel_last_accessed, MidpointRounding.AwayFromZero);
wheel_last_accessed = (int)wheel;
int result = (int)Math.Round(state.WheelPrecise - wheel_last_accessed, MidpointRounding.AwayFromZero);
wheel_last_accessed = state.Wheel;
return result;
}
}
@ -327,8 +302,8 @@ namespace OpenTK.Input
{
get
{
int result = pos.X - pos_last_accessed.X;
pos_last_accessed.X = pos.X;
int result = state.X - pos_last_accessed.X;
pos_last_accessed.X = state.X;
return result;
}
}
@ -345,8 +320,8 @@ namespace OpenTK.Input
{
get
{
int result = pos.Y - pos_last_accessed.Y;
pos_last_accessed.Y = pos.Y;
int result = state.Y - pos_last_accessed.Y;
pos_last_accessed.Y = state.Y;
return result;
}
}
@ -357,286 +332,4 @@ namespace OpenTK.Input
#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
// 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;
float wheel;
MouseScrollWheel scroll;
ushort buttons;
bool is_connected;
#endregion
@ -93,7 +89,7 @@ namespace OpenTK.Input
/// </summary>
public int Wheel
{
get { return (int)Math.Round(wheel, MidpointRounding.AwayFromZero); }
get { return (int)Math.Round(scroll.Y, MidpointRounding.AwayFromZero); }
}
/// <summary>
@ -101,11 +97,16 @@ namespace OpenTK.Input
/// </summary>
public float WheelPrecise
{
get { return wheel; }
internal set
{
wheel = value;
}
get { return scroll.Y; }
}
/// <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>
@ -253,13 +254,18 @@ namespace OpenTK.Input
/// </returns>
public override int GetHashCode()
{
unsafe
{
fixed (int* b = Buttons)
{
return b->GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ WheelPrecise.GetHashCode();
}
}
return buttons.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ scroll.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
@ -269,64 +275,28 @@ namespace OpenTK.Input
internal bool ReadBit(int offset)
{
ValidateOffset(offset);
int int_offset = offset / 32;
int bit_offset = offset % 32;
unsafe
{
fixed (int* b = Buttons)
{
return (*(b + int_offset) & (1 << bit_offset)) != 0u;
}
}
return (buttons & (1 << offset)) != 0;
}
internal void EnableBit(int offset)
{
ValidateOffset(offset);
int int_offset = offset / 32;
int bit_offset = offset % 32;
unsafe
{
fixed (int* b = Buttons)
{
*(b + int_offset) |= 1 << bit_offset;
}
}
buttons |= unchecked((ushort)(1 << offset));
}
internal void DisableBit(int offset)
{
ValidateOffset(offset);
int int_offset = offset / 32;
int bit_offset = offset % 32;
unsafe
{
fixed (int* b = Buttons)
{
*(b + int_offset) &= ~(1 << bit_offset);
}
}
buttons &= unchecked((ushort)(~(1 << offset)));
}
internal void MergeBits(MouseState other)
{
unsafe
{
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;
Y += other.Y;
IsConnected |= other.IsConnected;
}
buttons |= other.buttons;
SetScrollRelative(other.scroll.X, other.scroll.Y);
X += other.X;
Y += other.Y;
IsConnected |= other.IsConnected;
}
internal void SetIsConnected(bool value)
@ -334,13 +304,29 @@ namespace OpenTK.Input
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
#region Private Members
static void ValidateOffset(int offset)
{
if (offset < 0 || offset >= NumInts * IntSize)
if (offset < 0 || offset >= 16)
throw new ArgumentOutOfRangeException("offset");
}
@ -355,18 +341,11 @@ namespace OpenTK.Input
/// <returns>True, if both instances are equal; false otherwise.</returns>
public bool Equals(MouseState other)
{
bool equal = true;
unsafe
{
int* b2 = other.Buttons;
fixed (int* b1 = Buttons)
{
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;
return
buttons == other.buttons &&
X == other.X &&
Y == other.Y &&
Scroll == other.Scroll;
}
#endregion

View file

@ -163,12 +163,7 @@ namespace OpenTK
/// </returns>
public Point PointToScreen(Point point)
{
// Here we use the fact that PointToClient just translates the point, and PointToScreen
// should perform the inverse operation.
Point trans = PointToClient(Point.Empty);
point.X -= trans.X;
point.Y -= trans.Y;
return point;
return implementation.PointToScreen(point);
}
#endregion
@ -680,6 +675,26 @@ namespace OpenTK
/// </summary>
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
@ -902,6 +917,54 @@ namespace OpenTK
#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
/// <summary>
@ -1054,6 +1117,11 @@ namespace OpenTK
#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
private void OnMoveInternal(object sender, EventArgs e) { OnMove(e); }
@ -1116,6 +1184,10 @@ namespace OpenTK
implementation.KeyUp += OnKeyUpInternal;
implementation.MouseEnter += OnMouseEnterInternal;
implementation.MouseLeave += OnMouseLeaveInternal;
implementation.MouseDown += OnMouseDownInternal;
implementation.MouseUp += OnMouseUpInternal;
implementation.MouseMove += OnMouseMoveInternal;
implementation.MouseWheel += OnMouseWheelInternal;
implementation.Move += OnMoveInternal;
implementation.Resize += OnResizeInternal;
implementation.TitleChanged += OnTitleChangedInternal;
@ -1136,6 +1208,10 @@ namespace OpenTK
implementation.KeyUp -= OnKeyUpInternal;
implementation.MouseEnter -= OnMouseEnterInternal;
implementation.MouseLeave -= OnMouseLeaveInternal;
implementation.MouseDown -= OnMouseDownInternal;
implementation.MouseUp -= OnMouseUpInternal;
implementation.MouseMove -= OnMouseMoveInternal;
implementation.MouseWheel -= OnMouseWheelInternal;
implementation.Move -= OnMoveInternal;
implementation.Resize -= OnResizeInternal;
implementation.TitleChanged -= OnTitleChangedInternal;

View file

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

View file

@ -42,18 +42,33 @@ namespace OpenTK.Platform
readonly LegacyJoystickDriver JoystickDriver = new LegacyJoystickDriver();
internal LegacyInputDriver()
internal LegacyInputDriver(INativeWindow window)
{
dummy_mice_list.Add(new MouseDevice());
Mouse[0].Description = "Standard Mouse";
Mouse[0].NumberOfButtons = 3;
Mouse[0].NumberOfWheels = 1;
if (window == null)
throw new ArgumentNullException();
dummy_keyboard_list.Add(new KeyboardDevice());
Keyboard[0].Description = "Standard Keyboard";
Keyboard[0].NumberOfKeys = 101;
Keyboard[0].NumberOfLeds = 3;
Keyboard[0].NumberOfFunctionKeys = 12;
var mouse = new MouseDevice();
mouse.Description = "Standard Mouse";
mouse.NumberOfButtons = 3;
mouse.NumberOfWheels = 1;
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

View file

@ -29,7 +29,7 @@ using System;
using System.Collections.Generic;
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

View file

@ -35,6 +35,11 @@ namespace OpenTK.Platform.MacOS
{
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)]
extern static IntPtr class_getName(IntPtr handle);

View file

@ -57,9 +57,15 @@ namespace OpenTK.Platform.MacOS
[DllImport(LibObjC, EntryPoint="objc_msgSend")]
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")]
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")]
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()
{
// 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
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]).
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 { };

View file

@ -1,4 +1,4 @@
#region License
#region License
//
// CocoaNativeWindow.cs
//
@ -38,30 +38,14 @@ using OpenTK.Input;
namespace OpenTK.Platform.MacOS
{
class CocoaNativeWindow : INativeWindow
class CocoaNativeWindow : NativeWindowBase
{
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 selSendEvent = Selector.Get("sendEvent:");
//static readonly IntPtr selUpdateWindows = Selector.Get("updateWindows");
static readonly IntPtr selContentView = Selector.Get("contentView");
static readonly IntPtr selConvertRectFromScreen = Selector.Get("convertRectFromScreen:");
static readonly IntPtr selConvertRectToScreen = Selector.Get("convertRectToScreen:");
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 selHide = Selector.Get("hide");
static readonly IntPtr selUnhide = Selector.Get("unhide");
static readonly IntPtr selScrollingDeltaX = Selector.Get("scrollingDeltaX");
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 selSetStyleMask = Selector.Get("setStyleMask:");
static readonly IntPtr selStyleMask = Selector.Get("styleMask");
@ -145,13 +132,10 @@ namespace OpenTK.Platform.MacOS
private bool exists;
private bool cursorVisible = true;
private System.Drawing.Icon icon;
private LegacyInputDriver inputDriver = new LegacyInputDriver();
private WindowBorder windowBorder = WindowBorder.Resizable;
private Nullable<WindowBorder> deferredWindowBorder;
private Nullable<WindowBorder> previousWindowBorder;
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 RectangleF previousBounds;
private int normalLevel;
@ -160,7 +144,7 @@ namespace OpenTK.Platform.MacOS
private bool cursorInsideWindow = true;
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;
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);
// 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 bufferingType = NSBackingStore.Buffered;
@ -259,7 +253,7 @@ namespace OpenTK.Platform.MacOS
GraphicsContext.CurrentContext.Update(windowInfo);
if (suppressResize == 0)
Resize(this, EventArgs.Empty);
OnResize(EventArgs.Empty);
}
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,
// not each frame as it is on PC.
Move(this, EventArgs.Empty);
OnMove(EventArgs.Empty);
}
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)
{
FocusedChanged(this, EventArgs.Empty);
OnFocusedChanged(EventArgs.Empty);
}
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)
{
windowState = WindowState.Minimized;
WindowStateChanged(this, EventArgs.Empty);
OnWindowStateChanged(EventArgs.Empty);
OnResize(false); // Don't set tracking area when we minimize
}
private void WindowDidDeminiaturize(IntPtr self, IntPtr cmd, IntPtr notification)
{
windowState = WindowState.Normal;
WindowStateChanged(this, EventArgs.Empty);
OnWindowStateChanged(EventArgs.Empty);
OnResize(true);
}
@ -321,7 +315,7 @@ namespace OpenTK.Platform.MacOS
InternalBounds = toFrame;
windowState = WindowState.Maximized;
WindowStateChanged(this, EventArgs.Empty);
OnWindowStateChanged(EventArgs.Empty);
}
return false;
}
@ -329,11 +323,11 @@ namespace OpenTK.Platform.MacOS
private bool WindowShouldClose(IntPtr self, IntPtr cmd, IntPtr sender)
{
var cancelArgs = new CancelEventArgs();
Closing(this, cancelArgs);
OnClosing(cancelArgs);
if (!cancelArgs.Cancel)
{
Closed(this, EventArgs.Empty);
OnClosed(EventArgs.Empty);
return true;
}
@ -377,7 +371,7 @@ namespace OpenTK.Platform.MacOS
Cocoa.SendVoid(owner, selAddTrackingArea, trackingArea);
}
public void Close()
public override void Close()
{
shouldClose = true;
}
@ -391,13 +385,6 @@ namespace OpenTK.Platform.MacOS
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)
{
if (cocoaButtonIndex == 0) return MouseButton.Left;
@ -409,8 +396,10 @@ namespace OpenTK.Platform.MacOS
return (MouseButton)cocoaButtonIndex;
}
public void ProcessEvents()
public override void ProcessEvents()
{
base.ProcessEvents();
while (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:
{
var keyCode = Cocoa.SendUshort(e, selKeyCode);
var modifierFlags = (NSEventModifierMask)Cocoa.SendUint(e, selModifierFlags);
MacOSKeyCode keyCode = (MacOSKeyCode)Cocoa.SendUshort(e, selKeyCode);
var isARepeat = Cocoa.SendBool(e, selIsARepeat);
GetKey(keyCode, modifierFlags, keyArgs);
InputDriver.Keyboard[0].SetKey(keyArgs.Key, keyArgs.ScanCode, true);
Key key = MacOSKeyMap.GetKey(keyCode);
if (!isARepeat || InputDriver.Keyboard[0].KeyRepeat)
{
KeyDown(this, keyArgs);
}
OnKeyDown(key, isARepeat);
var s = Cocoa.FromNSString(Cocoa.SendIntPtr(e, selCharactersIgnoringModifiers));
foreach (var c in s)
@ -440,10 +424,9 @@ namespace OpenTK.Platform.MacOS
int intVal = (int)c;
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.
keyPressArgs.KeyChar = c;
KeyPress(this, keyPressArgs);
// For some reason, arrow keys (mapped 63232-63235)
// are seen as non-control characters, so get rid of those.
OnKeyPress(c);
}
}
}
@ -451,13 +434,16 @@ namespace OpenTK.Platform.MacOS
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);
GetKey(keyCode, modifierFlags, keyArgs);
InputDriver.Keyboard[0].SetKey(keyArgs.Key, keyArgs.ScanCode, false);
KeyUp(this, keyArgs);
UpdateModifierFlags(GetModifiers(modifierFlags));
}
break;
@ -472,8 +458,7 @@ namespace OpenTK.Platform.MacOS
//SetCursor(selectedCursor);
}
cursorInsideWindow = true;
MouseEnter(this, EventArgs.Empty);
OnMouseEnter(EventArgs.Empty);
}
}
break;
@ -486,11 +471,10 @@ namespace OpenTK.Platform.MacOS
{
if (selectedCursor != MouseCursor.Default)
{
SetCursor(MouseCursor.Default);
//SetCursor(MouseCursor.Default);
}
cursorInsideWindow = false;
MouseLeave(this, EventArgs.Empty);
OnMouseLeave(EventArgs.Empty);
}
}
break;
@ -500,18 +484,38 @@ namespace OpenTK.Platform.MacOS
case NSEventType.OtherMouseDragged:
case NSEventType.MouseMoved:
{
var pf = Cocoa.SendPoint(e, selLocationInWindowOwner);
Point p = new Point(MouseState.X, MouseState.Y);
if (CursorVisible)
{
// Use absolute coordinates
var pf = Cocoa.SendPoint(e, selLocationInWindowOwner);
// Convert from points to pixel coordinates
var rf = Cocoa.SendRect(windowInfo.Handle, selConvertRectToBacking,
new RectangleF(pf.X, pf.Y, 0, 0));
// Convert from points to pixel coordinates
var rf = Cocoa.SendRect(windowInfo.Handle, selConvertRectToBacking,
new RectangleF(pf.X, pf.Y, 0, 0));
// See CocoaDrawingGuide under "Converting from Window to View Coordinates"
var p = new Point(
MathHelper.Clamp((int)Math.Round(rf.X), 0, Width),
MathHelper.Clamp((int)Math.Round(Height - rf.Y), 0, Height));
// See CocoaDrawingGuide under "Converting from Window to View Coordinates"
p = new Point(
MathHelper.Clamp((int)Math.Round(rf.X), 0, Width),
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;
@ -520,15 +524,23 @@ namespace OpenTK.Platform.MacOS
case NSEventType.ScrollWheel:
{
var scrollingDelta = Cocoa.SendFloat(e, selScrollingDeltaY);
var factor = 1.0f;
float dx, dy;
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;
@ -537,7 +549,7 @@ namespace OpenTK.Platform.MacOS
case NSEventType.OtherMouseDown:
{
var buttonNumber = Cocoa.SendInt(e, selButtonNumber);
InputDriver.Mouse[0][GetMouseButton(buttonNumber)] = true;
OnMouseDown(GetMouseButton(buttonNumber));
}
break;
@ -546,7 +558,7 @@ namespace OpenTK.Platform.MacOS
case NSEventType.OtherMouseUp:
{
var buttonNumber = Cocoa.SendInt(e, selButtonNumber);
InputDriver.Mouse[0][GetMouseButton(buttonNumber)] = false;
OnMouseUp(GetMouseButton(buttonNumber));
}
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));
return new Point((int)r.X, (int)(GetContentViewFrame().Height - GetCurrentScreenFrame().Height - r.Y));
var r =
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));
return new Point((int)r.X, (int)(-GetContentViewFrame().Height + GetCurrentScreenFrame().Height - r.Y));
var r =
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; }
set
@ -598,11 +616,11 @@ namespace OpenTK.Platform.MacOS
IntPtr nsimg = Cocoa.ToNSImage(img);
Cocoa.SendVoid(NSApplication.Handle, selSetApplicationIconImage, nsimg);
}
IconChanged(this, EventArgs.Empty);
OnIconChanged(EventArgs.Empty);
}
}
public string Title
public override string Title
{
get
{
@ -614,7 +632,7 @@ namespace OpenTK.Platform.MacOS
}
}
public bool Focused
public override bool Focused
{
get
{
@ -622,7 +640,7 @@ namespace OpenTK.Platform.MacOS
}
}
public bool Visible
public override bool Visible
{
get
{
@ -631,11 +649,11 @@ namespace OpenTK.Platform.MacOS
set
{
Cocoa.SendVoid(windowInfo.Handle, selSetIsVisible, value);
VisibleChanged(this, EventArgs.Empty);
OnVisibleChanged(EventArgs.Empty);
}
}
public bool Exists
public override bool Exists
{
get
{
@ -643,7 +661,7 @@ namespace OpenTK.Platform.MacOS
}
}
public IWindowInfo WindowInfo
public override IWindowInfo WindowInfo
{
get
{
@ -702,7 +720,7 @@ namespace OpenTK.Platform.MacOS
previousWindowBorder = null;
}
public WindowState WindowState
public override WindowState WindowState
{
get
{
@ -735,7 +753,7 @@ namespace OpenTK.Platform.MacOS
InternalBounds = GetCurrentScreenFrame();
windowState = value;
WindowStateChanged(this, EventArgs.Empty);
OnWindowStateChanged(EventArgs.Empty);
}
else if (value == WindowState.Maximized)
{
@ -748,13 +766,13 @@ namespace OpenTK.Platform.MacOS
else if (value == WindowState.Normal)
{
windowState = value;
WindowStateChanged(this, EventArgs.Empty);
Resize(this, EventArgs.Empty);
OnWindowStateChanged(EventArgs.Empty);
OnResize(EventArgs.Empty);
}
}
}
public WindowBorder WindowBorder
public override WindowBorder WindowBorder
{
get
{
@ -773,7 +791,7 @@ namespace OpenTK.Platform.MacOS
return;
SetWindowBorder(value);
WindowBorderChanged(this, EventArgs.Empty);
OnWindowBorderChanged(EventArgs.Empty);
}
}
@ -795,16 +813,26 @@ namespace OpenTK.Platform.MacOS
return (NSWindowStyle)0;
}
public System.Drawing.Rectangle Bounds
public override System.Drawing.Rectangle Bounds
{
get
{
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
{
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
{
var contentViewBounds = Cocoa.SendRect(windowInfo.ViewHandle, selBounds);
var bounds = Cocoa.SendRect(windowInfo.Handle, selConvertRectToBacking, contentViewBounds);
return new Rectangle((int)bounds.X, (int)bounds.Y, (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;
return new Size((int)bounds.Width, (int)bounds.Height);
}
set
{
@ -928,15 +864,7 @@ namespace OpenTK.Platform.MacOS
}
}
public OpenTK.Input.IInputDriver InputDriver
{
get
{
return inputDriver;
}
}
public MouseCursor Cursor
public override MouseCursor Cursor
{
get
{
@ -1058,7 +986,7 @@ namespace OpenTK.Platform.MacOS
Cocoa.SendVoid(windowInfo.Handle, selInvalidateCursorRectsForView, windowInfo.ViewHandle);
}
public bool CursorVisible
public override bool CursorVisible
{
get { return cursorVisible; }
set
@ -1075,13 +1003,7 @@ namespace OpenTK.Platform.MacOS
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
protected override void Dispose(bool disposing)
{
if (disposed)
return;
@ -1105,12 +1027,12 @@ namespace OpenTK.Platform.MacOS
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()
@ -1135,25 +1057,27 @@ namespace OpenTK.Platform.MacOS
private void SetCursorVisible(bool visible)
{
// If the mouse is outside the window and we want to hide it,
// 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);
}
Carbon.CG.AssociateMouseAndMouseCursorPosition(visible);
Cocoa.SendVoid(NSCursor, visible ? selUnhide : selHide);
}
private void SetCursor(MouseCursor cursor)
{
if (cursor == MouseCursor.Default)
{
Cocoa.SendVoid(NSCursor, selUnhide);
}
else if (cursor == MouseCursor.Empty)
{
Cocoa.SendVoid(NSCursor, selHide);
}
else
{
}
}
private void SetMenuVisible(bool visible)
{
var options = (NSApplicationPresentationOptions)Cocoa.SendInt(NSApplication.Handle, selPresentationOptions);
@ -1178,7 +1102,7 @@ namespace OpenTK.Platform.MacOS
Cocoa.SendIntPtr(windowInfo.Handle, selSetTitle, Cocoa.ToNSString(title));
if (callEvent)
{
TitleChanged(this, EventArgs.Empty);
OnTitleChanged(EventArgs.Empty);
}
}

View file

@ -324,7 +324,7 @@ namespace OpenTK.Platform.MacOS
break;
case HIDUsageGD.Wheel:
mouse.State.WheelPrecise += v_int;
mouse.State.SetScrollRelative(0, v_int);
break;
}
break;
@ -332,6 +332,15 @@ namespace OpenTK.Platform.MacOS
case HIDPage.Button:
mouse.State[OpenTK.Input.MouseButton.Left + usage - 1] = v_int == 1;
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);
}
keyboard.State.SetKeyState(RawKeyMap[usage], (byte)usage, v_int != 0);
keyboard.State[RawKeyMap[usage]] = v_int != 0;
break;
}
}
@ -1107,6 +1117,12 @@ namespace OpenTK.Platform.MacOS
VendorDefinedStart = 0xFF00
}
// Consumer electronic devices
enum HIDUsageCD
{
ACPan = 0x0238
}
// Generic desktop usage
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 Button Button;
public State State;
public byte Clicks;
byte padding1;
byte padding2;
public Int32 X;
public Int32 Y;
}
@ -1584,10 +1584,7 @@ namespace OpenTK.Platform.SDL2
public uint Timestamp;
public uint WindowID;
public uint Which;
public State State;
byte padding1;
byte padding2;
byte padding3;
public ButtonFlags State;
public Int32 X;
public Int32 Y;
public Int32 Xrel;
@ -1617,10 +1614,6 @@ namespace OpenTK.Platform.SDL2
}
public const uint TouchMouseID = 0xffffffff;
public static class GL
{
}
}
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)
{
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()

View file

@ -34,7 +34,7 @@ using OpenTK.Input;
namespace OpenTK.Platform.SDL2
{
class Sdl2InputDriver : IInputDriver2, IInputDriver
class Sdl2InputDriver : IInputDriver2
{
readonly static Dictionary<IntPtr, Sdl2InputDriver> DriverHandles =
new Dictionary<IntPtr, Sdl2InputDriver>();
@ -154,51 +154,6 @@ namespace OpenTK.Platform.SDL2
#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
public IMouseDriver2 MouseDriver

View file

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

View file

@ -33,28 +33,18 @@ using OpenTK.Input;
namespace OpenTK.Platform.SDL2
{
class Sdl2Mouse : IMouseDriver2, IMouseDriver
class Sdl2Mouse : IMouseDriver2
{
MouseState state;
readonly List<MouseDevice> mice =
new List<MouseDevice>();
readonly IList<MouseDevice> mice_readonly;
public Sdl2Mouse()
{
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
MouseButton TranslateButton(Button button)
static internal MouseButton TranslateButton(Button button)
{
switch (button)
{
@ -97,34 +87,19 @@ namespace OpenTK.Platform.SDL2
public void ProcessWheelEvent(MouseWheelEvent wheel)
{
state.WheelPrecise += wheel.Y;
mice[0].WheelPrecise += wheel.Y;
state.SetScrollRelative(0, wheel.Y);
}
public void ProcessMouseEvent(MouseMotionEvent motion)
{
state.X += motion.Xrel;
state.Y += motion.Yrel;
mice[0].Position = new Point(motion.X, motion.Y);
}
public void ProcessMouseEvent(MouseButtonEvent button)
{
bool pressed = button.State == State.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

View file

@ -41,7 +41,7 @@ using System.Text;
namespace OpenTK.Platform.SDL2
{
class Sdl2NativeWindow : INativeWindow, IInputDriver
class Sdl2NativeWindow : NativeWindowBase
{
readonly object sync = new object();
@ -66,25 +66,14 @@ namespace OpenTK.Platform.SDL2
// to .Net UTF16 strings
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 =
new Dictionary<uint, Sdl2NativeWindow>();
public Sdl2NativeWindow(int x, int y, int width, int height,
string title, GameWindowFlags options, DisplayDevice device,
IInputDriver input_driver)
string title, GameWindowFlags options, DisplayDevice device)
{
lock (sync)
{
this.input_driver = input_driver;
var bounds = device.Bounds;
var flags = TranslateFlags(options);
flags |= WindowFlags.OPENGL;
@ -180,7 +169,7 @@ namespace OpenTK.Platform.SDL2
case EventType.MOUSEBUTTONUP:
if (windows.TryGetValue(ev.Button.WindowID, out window))
{
ProcessButtonEvent(window, ev);
ProcessMouseButtonEvent(window, ev.Button);
processed = true;
}
break;
@ -188,7 +177,7 @@ namespace OpenTK.Platform.SDL2
case EventType.MOUSEMOTION:
if (windows.TryGetValue(ev.Motion.WindowID, out window))
{
ProcessMotionEvent(window, ev);
ProcessMouseMotionEvent(window, ev.Motion);
processed = true;
}
break;
@ -196,7 +185,7 @@ namespace OpenTK.Platform.SDL2
case EventType.MOUSEWHEEL:
if (windows.TryGetValue(ev.Wheel.WindowID, out window))
{
ProcessWheelEvent(window, ev);
ProcessMouseWheelEvent(window, ev.Wheel);
processed = true;
}
break;
@ -214,9 +203,9 @@ namespace OpenTK.Platform.SDL2
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
// outside the window. SetWindowGrab ensures we get them.
@ -225,24 +214,30 @@ namespace OpenTK.Platform.SDL2
SDL.SetWindowGrab(window.window.Handle,
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)
{
bool key_pressed = ev.Key.State == State.Pressed;
var key = ev.Key.Keysym;
window.key_args.Key = TranslateKey(key.Scancode);
window.key_args.ScanCode = (uint)key.Scancode;
window.key_args.Modifiers = window.input_driver.Keyboard[0].GetModifiers();
Key key = TranslateKey(ev.Key.Keysym.Scancode);
if (key_pressed)
{
window.KeyDown(window, window.key_args);
window.OnKeyDown(key, ev.Key.Repeat > 0);
}
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)
@ -273,21 +268,21 @@ namespace OpenTK.Platform.SDL2
for (int i = 0; i < decoded_length; i++)
{
window.keypress_args.KeyChar = window.DecodeTextBuffer[i];
window.KeyPress(window, window.keypress_args);
window.OnKeyPress(window.DecodeTextBuffer[i]);
}
}
static void ProcessMotionEvent(Sdl2NativeWindow window, Event ev)
static void ProcessMouseMotionEvent(Sdl2NativeWindow window, MouseMotionEvent ev)
{
float scale = window.ClientSize.Width / (float)window.Size.Width;
//window.mouse.Position = new Point(
// (int)(ev.motion.x * scale), (int)(ev.motion.y * scale));
window.OnMouseMove(
(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)
@ -299,7 +294,7 @@ namespace OpenTK.Platform.SDL2
try
{
window.is_in_closing_event = true;
window.Closing(window, close_args);
window.OnClosing(close_args);
}
finally
{
@ -308,17 +303,17 @@ namespace OpenTK.Platform.SDL2
if (!close_args.Cancel)
{
window.Closed(window, EventArgs.Empty);
window.OnClosed(EventArgs.Empty);
window.must_destroy = true;
}
break;
case WindowEventID.ENTER:
window.MouseEnter(window, EventArgs.Empty);
window.OnMouseEnter(EventArgs.Empty);
break;
case WindowEventID.LEAVE:
window.MouseLeave(window, EventArgs.Empty);
window.OnMouseLeave(EventArgs.Empty);
break;
case WindowEventID.EXPOSED:
@ -327,47 +322,47 @@ namespace OpenTK.Platform.SDL2
case WindowEventID.FOCUS_GAINED:
window.is_focused = true;
window.FocusedChanged(window, EventArgs.Empty);
window.OnFocusedChanged(EventArgs.Empty);
break;
case WindowEventID.FOCUS_LOST:
window.is_focused = false;
window.FocusedChanged(window, EventArgs.Empty);
window.OnFocusedChanged(EventArgs.Empty);
break;
case WindowEventID.HIDDEN:
window.is_visible = false;
window.VisibleChanged(window, EventArgs.Empty);
window.OnVisibleChanged(EventArgs.Empty);
break;
case WindowEventID.SHOWN:
window.is_visible = true;
window.VisibleChanged(window, EventArgs.Empty);
window.OnVisibleChanged(EventArgs.Empty);
break;
case WindowEventID.MAXIMIZED:
window.window_state = WindowState.Maximized;
window.WindowStateChanged(window, EventArgs.Empty);
window.OnWindowStateChanged(EventArgs.Empty);
break;
case WindowEventID.MINIMIZED:
window.previous_window_state = window.window_state;
window.window_state = WindowState.Minimized;
window.WindowStateChanged(window, EventArgs.Empty);
window.OnWindowStateChanged(EventArgs.Empty);
break;
case WindowEventID.RESTORED:
window.window_state = window.previous_window_state;
window.WindowStateChanged(window, EventArgs.Empty);
window.OnWindowStateChanged(EventArgs.Empty);
break;
case WindowEventID.MOVED:
window.Move(window, EventArgs.Empty);
window.OnMove(EventArgs.Empty);
break;
case WindowEventID.RESIZED:
case WindowEventID.SIZE_CHANGED:
window.Resize(window, EventArgs.Empty);
window.OnResize(EventArgs.Empty);
break;
default:
@ -402,6 +397,16 @@ namespace OpenTK.Platform.SDL2
SDL.ShowCursor(!grab);
SDL.SetWindowGrab(window.Handle, 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
@ -443,24 +448,7 @@ namespace OpenTK.Platform.SDL2
#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> MouseEnter = delegate { };
public event EventHandler<EventArgs> MouseLeave = delegate { };
public MouseCursor Cursor
public override MouseCursor Cursor
{
get
{
@ -540,7 +528,7 @@ namespace OpenTK.Platform.SDL2
}
}
public void Close()
public override void Close()
{
lock (sync)
{
@ -560,8 +548,9 @@ namespace OpenTK.Platform.SDL2
}
}
public void ProcessEvents()
public override void ProcessEvents()
{
base.ProcessEvents();
lock (sync)
{
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 client = Location;
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 client = Location;
return new Point(point.X + origin.X - client.X, point.Y + origin.Y - client.Y);
}
public Icon Icon
public override Icon Icon
{
get
{
@ -639,13 +628,13 @@ namespace OpenTK.Platform.SDL2
}
icon = value;
IconChanged(this, EventArgs.Empty);
OnIconChanged(EventArgs.Empty);
}
}
}
}
public string Title
public override string Title
{
get
{
@ -671,7 +660,7 @@ namespace OpenTK.Platform.SDL2
}
}
public bool Focused
public override bool Focused
{
get
{
@ -679,7 +668,7 @@ namespace OpenTK.Platform.SDL2
}
}
public bool Visible
public override bool Visible
{
get
{
@ -700,7 +689,7 @@ namespace OpenTK.Platform.SDL2
}
}
public bool Exists
public override bool Exists
{
get
{
@ -708,7 +697,7 @@ namespace OpenTK.Platform.SDL2
}
}
public IWindowInfo WindowInfo
public override IWindowInfo WindowInfo
{
get
{
@ -716,7 +705,7 @@ namespace OpenTK.Platform.SDL2
}
}
public WindowState WindowState
public override WindowState WindowState
{
get
{
@ -774,7 +763,7 @@ namespace OpenTK.Platform.SDL2
}
}
public WindowBorder WindowBorder
public override WindowBorder WindowBorder
{
get
{
@ -810,13 +799,13 @@ namespace OpenTK.Platform.SDL2
if (Exists)
{
WindowBorderChanged(this, EventArgs.Empty);
OnWindowBorderChanged(EventArgs.Empty);
}
}
}
}
public Rectangle Bounds
public override Rectangle Bounds
{
get
{
@ -829,7 +818,7 @@ namespace OpenTK.Platform.SDL2
}
}
public Point Location
public override Point Location
{
get
{
@ -856,7 +845,7 @@ namespace OpenTK.Platform.SDL2
}
}
public Size Size
public override Size Size
{
get
{
@ -883,67 +872,7 @@ namespace OpenTK.Platform.SDL2
}
}
public int X
{
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
public override Size ClientSize
{
get
{
@ -967,15 +896,7 @@ namespace OpenTK.Platform.SDL2
}
}
public IInputDriver InputDriver
{
get
{
return input_driver;
}
}
public bool CursorVisible
public override bool CursorVisible
{
get
{
@ -996,54 +917,9 @@ namespace OpenTK.Platform.SDL2
#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
void Dispose(bool manual)
protected override void Dispose(bool manual)
{
if (!disposed)
{
@ -1082,17 +958,6 @@ namespace OpenTK.Platform.SDL2
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Sdl2NativeWindow()
{
Dispose(true);
}
#endregion
}
}

View file

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

View file

@ -44,7 +44,7 @@ namespace OpenTK.Platform.Windows
/// Drives GameWindow on Windows.
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
/// </summary>
internal sealed class WinGLNative : INativeWindow, IInputDriver
internal sealed class WinGLNative : NativeWindowBase
{
#region Fields
@ -82,12 +82,6 @@ namespace OpenTK.Platform.Windows
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.
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 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;
IntPtr cursor_handle = Functions.LoadCursor(CursorName.Arrow);
int cursor_visible_count = 0;
@ -160,18 +150,6 @@ namespace OpenTK.Platform.Windows
window);
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;
if (new_focused_state != Focused)
FocusedChanged(this, EventArgs.Empty);
OnFocusedChanged(EventArgs.Empty);
}
void HandleEnterModalLoop(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
@ -292,7 +270,7 @@ namespace OpenTK.Platform.Windows
if (Location != new_location)
{
bounds.Location = new_location;
Move(this, EventArgs.Empty);
OnMove(EventArgs.Empty);
}
Size new_size = new Size(pos->cx, pos->cy);
@ -310,7 +288,7 @@ namespace OpenTK.Platform.Windows
SetWindowPosFlags.NOACTIVATE | SetWindowPosFlags.NOSENDCHANGING);
if (suppress_resize <= 0)
Resize(this, EventArgs.Empty);
OnResize(EventArgs.Empty);
}
if (!is_in_modal_loop)
@ -352,7 +330,7 @@ namespace OpenTK.Platform.Windows
GrabCursor();
windowBorder = new_border;
WindowBorderChanged(this, EventArgs.Empty);
OnWindowBorderChanged(EventArgs.Empty);
}
}
@ -380,7 +358,7 @@ namespace OpenTK.Platform.Windows
if (new_state != windowState)
{
windowState = new_state;
WindowStateChanged(this, EventArgs.Empty);
OnWindowStateChanged(EventArgs.Empty);
// Ensure cursor remains grabbed
if (!CursorVisible)
@ -415,8 +393,7 @@ namespace OpenTK.Platform.Windows
if (!Char.IsControl(c))
{
key_press.KeyChar = c;
KeyPress(this, key_press);
OnKeyPress(c);
}
}
@ -442,8 +419,7 @@ namespace OpenTK.Platform.Windows
};
// Max points GetMouseMovePointsEx can return is 64.
int numPoints = 64;
const int numPoints = 64;
MouseMovePoint* movePoints = stackalloc MouseMovePoint[numPoints];
// 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))
{
// Just use the mouse move position
mouse.Position = point;
OnMouseMove(point.X, point.Y);
}
else if (points == -1)
{
@ -468,7 +444,7 @@ namespace OpenTK.Platform.Windows
else
{
// 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);
// Find the first move point we've already seen.
@ -497,7 +473,7 @@ namespace OpenTK.Platform.Windows
position.Y -= 65536;
}
Functions.ScreenToClient(handle, ref position);
mouse.Position = position;
OnMouseMove(position.X, position.Y);
}
}
mouse_last_timestamp = timestamp;
@ -510,7 +486,7 @@ namespace OpenTK.Platform.Windows
mouse_outside_window = false;
EnableMouseTracking();
MouseEnter(this, EventArgs.Empty);
OnMouseEnter(EventArgs.Empty);
}
}
@ -519,64 +495,75 @@ namespace OpenTK.Platform.Windows
mouse_outside_window = true;
// 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)
{
// This is due to inconsistent behavior of the WParam value on 64bit arch, whese
// wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000
mouse.WheelPrecise += ((long)wParam << 32 >> 48) / 120.0f;
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)
{
Functions.SetCapture(window.Handle);
mouse[MouseButton.Left] = true;
OnMouseDown(MouseButton.Left);
}
void HandleMButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.SetCapture(window.Handle);
mouse[MouseButton.Middle] = true;
OnMouseDown(MouseButton.Middle);
}
void HandleRButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.SetCapture(window.Handle);
mouse[MouseButton.Right] = true;
OnMouseDown(MouseButton.Right);
}
void HandleXButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.SetCapture(window.Handle);
mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2] = true;
MouseButton button =
((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2;
OnMouseDown(button);
}
void HandleLButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.ReleaseCapture();
mouse[MouseButton.Left] = false;
OnMouseUp(MouseButton.Left);
}
void HandleMButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.ReleaseCapture();
mouse[MouseButton.Middle] = false;
OnMouseUp(MouseButton.Middle);
}
void HandleRButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.ReleaseCapture();
mouse[MouseButton.Right] = false;
OnMouseUp(MouseButton.Right);
}
void HandleXButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.ReleaseCapture();
mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2] = false;
MouseButton button =
((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2;
OnMouseUp(button);
}
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.
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;
bool is_valid;
Key key = WinKeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid);
if (is_valid)
{
keyboard.SetKey(key, (byte)scancode, pressed);
if (pressed)
{
key_down.Key = key;
key_down.Modifiers = keyboard.GetModifiers();
KeyDown(this, key_down);
//OnKeyDown(key, repeat_count > 0);
OnKeyDown(key, KeyboardState[key]);
}
else
{
key_up.Key = key;
key_up.Modifiers = keyboard.GetModifiers();
KeyUp(this, key_up);
OnKeyUp(key);
}
}
}
void HandleKillFocus(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
keyboard.ClearKeys();
}
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();
Closing(this, e);
OnClosing(e);
if (!e.Cancel)
{
@ -663,7 +645,7 @@ namespace OpenTK.Platform.Windows
window.Dispose();
child_window.Dispose();
Closed(this, EventArgs.Empty);
OnClosed(EventArgs.Empty);
}
#endregion
@ -731,6 +713,10 @@ namespace OpenTK.Platform.Windows
HandleMouseWheel(handle, message, wParam, lParam);
break;
case WindowMessage.MOUSEHWHEEL:
HandleMouseHWheel(handle, message, wParam, lParam);
break;
case WindowMessage.LBUTTONDOWN:
HandleLButtonDown(handle, message, wParam, lParam);
break;
@ -927,7 +913,6 @@ namespace OpenTK.Platform.Windows
{
suppress_resize++;
WindowBorder = WindowBorder.Hidden;
ProcessEvents();
suppress_resize--;
}
@ -938,7 +923,6 @@ namespace OpenTK.Platform.Windows
deferred_window_border.HasValue ? deferred_window_border.Value :
previous_window_border.HasValue ? previous_window_border.Value :
WindowBorder;
ProcessEvents();
suppress_resize--;
deferred_window_border = previous_window_border = null;
}
@ -947,7 +931,6 @@ namespace OpenTK.Platform.Windows
{
suppress_resize++;
WindowState = WindowState.Normal;
ProcessEvents();
suppress_resize--;
}
@ -977,7 +960,7 @@ namespace OpenTK.Platform.Windows
#region Bounds
public Rectangle Bounds
public override Rectangle Bounds
{
get { return bounds; }
set
@ -991,7 +974,7 @@ namespace OpenTK.Platform.Windows
#region Location
public Point Location
public override Point Location
{
get { return Bounds.Location; }
set
@ -1005,7 +988,7 @@ namespace OpenTK.Platform.Windows
#region Size
public Size Size
public override Size Size
{
get { return Bounds.Size; }
set
@ -1017,36 +1000,13 @@ namespace OpenTK.Platform.Windows
#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
public Size ClientSize
public override Size ClientSize
{
get
{
return ClientRectangle.Size;
return client_rectangle.Size;
}
set
{
@ -1059,49 +1019,9 @@ namespace OpenTK.Platform.Windows
#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
public Icon Icon
public override Icon Icon
{
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)1, icon == null ? IntPtr.Zero : value.Handle);
}
IconChanged(this, EventArgs.Empty);
OnIconChanged(EventArgs.Empty);
}
}
}
@ -1126,7 +1046,7 @@ namespace OpenTK.Platform.Windows
#region Focused
public bool Focused
public override bool Focused
{
get { return focused; }
}
@ -1136,7 +1056,7 @@ namespace OpenTK.Platform.Windows
#region Title
StringBuilder sb_title = new StringBuilder(256);
public string Title
public override string Title
{
get
{
@ -1151,7 +1071,7 @@ namespace OpenTK.Platform.Windows
{
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());
TitleChanged(this, EventArgs.Empty);
OnTitleChanged(EventArgs.Empty);
}
}
}
@ -1160,7 +1080,7 @@ namespace OpenTK.Platform.Windows
#region Visible
public bool Visible
public override bool Visible
{
get
{
@ -1184,7 +1104,7 @@ namespace OpenTK.Platform.Windows
Functions.ShowWindow(window.Handle, ShowWindowCommand.HIDE);
}
VisibleChanged(this, EventArgs.Empty);
OnVisibleChanged(EventArgs.Empty);
}
}
}
@ -1193,13 +1113,13 @@ namespace OpenTK.Platform.Windows
#region Exists
public bool Exists { get { return exists; } }
public override bool Exists { get { return exists; } }
#endregion
#region Cursor
public MouseCursor Cursor
public override MouseCursor Cursor
{
get
{
@ -1270,8 +1190,8 @@ namespace OpenTK.Platform.Windows
#endregion
#region CursorVisible
public bool CursorVisible
public override bool CursorVisible
{
get { return cursor_visible_count >= 0; } // Not used
set
@ -1303,7 +1223,7 @@ namespace OpenTK.Platform.Windows
#region Close
public void Close()
public override void Close()
{
Functions.PostMessage(window.Handle, WindowMessage.CLOSE, IntPtr.Zero, IntPtr.Zero);
}
@ -1312,7 +1232,7 @@ namespace OpenTK.Platform.Windows
#region public WindowState WindowState
public WindowState WindowState
public override WindowState WindowState
{
get
{
@ -1325,12 +1245,12 @@ namespace OpenTK.Platform.Windows
ShowWindowCommand command = 0;
bool exiting_fullscreen = false;
borderless_maximized_window_state = false;
switch (value)
{
case WindowState.Normal:
command = ShowWindowCommand.RESTORE;
borderless_maximized_window_state = false;
// If we are leaving fullscreen mode we need to restore the border.
if (WindowState == WindowState.Fullscreen)
@ -1358,6 +1278,7 @@ namespace OpenTK.Platform.Windows
}
else
{
borderless_maximized_window_state = false;
command = ShowWindowCommand.MAXIMIZE;
}
break;
@ -1406,7 +1327,7 @@ namespace OpenTK.Platform.Windows
#region public WindowBorder WindowBorder
public WindowBorder WindowBorder
public override WindowBorder WindowBorder
{
get
{
@ -1500,7 +1421,7 @@ namespace OpenTK.Platform.Windows
#region PointToClient
public Point PointToClient(Point point)
public override Point PointToClient(Point point)
{
if (!Functions.ScreenToClient(window.Handle, ref point))
throw new InvalidOperationException(String.Format(
@ -1514,7 +1435,7 @@ namespace OpenTK.Platform.Windows
#region PointToScreen
public Point PointToScreen(Point point)
public override Point PointToScreen(Point point)
{
if (!Functions.ClientToScreen(window.Handle, ref point))
throw new InvalidOperationException(String.Format(
@ -1526,27 +1447,6 @@ namespace OpenTK.Platform.Windows
#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
#region INativeGLWindow Members
@ -1554,8 +1454,9 @@ namespace OpenTK.Platform.Windows
#region public void ProcessEvents()
MSG msg;
public void ProcessEvents()
public override void ProcessEvents()
{
base.ProcessEvents();
while (Functions.PeekMessage(ref msg, IntPtr.Zero, 0, 0, PeekMessageFlags.Remove))
{
Functions.TranslateMessage(ref msg);
@ -1565,18 +1466,9 @@ namespace OpenTK.Platform.Windows
#endregion
#region public IInputDriver InputDriver
public IInputDriver InputDriver
{
get { return this; }
}
#endregion
#region public IWindowInfo WindowInfo
public IWindowInfo WindowInfo
public override IWindowInfo WindowInfo
{
get { return child_window; }
}
@ -1585,62 +1477,9 @@ namespace OpenTK.Platform.Windows
#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
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
void Dispose(bool calledManually)
protected override void Dispose(bool calledManually)
{
if (!disposed)
{
@ -1662,16 +1501,11 @@ namespace OpenTK.Platform.Windows
Debug.Print("[Warning] INativeWindow leaked ({0}). Did you forget to call INativeWindow.Dispose()?", this);
}
Disposed(this, EventArgs.Empty);
OnDisposed(EventArgs.Empty);
disposed = true;
}
}
~WinGLNative()
{
Dispose(false);
}
#endregion
}
}

View file

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

View file

@ -227,7 +227,10 @@ namespace OpenTK.Platform.Windows
}
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)
{

View file

@ -266,7 +266,14 @@ namespace OpenTK.Platform.X11
static string[] EntryPointNames = new string[]
{
"glXCreateContextAttribs",
"glXSwapIntervalEXT",
"glXGetSwapIntervalEXT",
"glXSwapIntervalMESA",
"glXGetSwapIntervalMESA",
"glXSwapIntervalOML",
"glXGetSwapIntervalOML",
"glXSwapIntervalSGI",
"glXGetSwapIntervalSGI",
};
static IntPtr[] EntryPoints = new IntPtr[EntryPointNames.Length];
@ -405,6 +412,36 @@ namespace OpenTK.Platform.X11
#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
{
[AutoGenerated(EntryPoint = "glXSwapIntervalSGI")]
@ -412,6 +449,12 @@ namespace OpenTK.Platform.X11
{
throw new NotImplementedException();
}
[AutoGenerated(EntryPoint = "glXGetSwapIntervalSGI")]
public static int GetSwapInterval()
{
throw new NotImplementedException();
}
}
[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);
[Slot(1)]
[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
}

View file

@ -1707,7 +1707,7 @@ namespace OpenTK.Platform.X11
public double root_y;
public double event_x;
public double event_y;
public int flags;
public XIEventFlags flags;
public XIButtonState buttons;
public XIValuatorState valuators;
public XIModifierState mods;
@ -1828,4 +1828,32 @@ namespace OpenTK.Platform.X11
RawButtonReleaseMask = (1 << (int)XIEventType.RawButtonRelease),
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.
IntPtr display;
X11WindowInfo currentWindow;
bool vsync_supported;
bool vsync_ext_supported;
bool vsync_mesa_supported;
bool vsync_sgi_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();
string extensions = null;
#endregion
@ -232,7 +235,7 @@ namespace OpenTK.Platform.X11
return result;
}
static bool SupportsExtension(IntPtr display, X11WindowInfo window, string e)
bool SupportsExtension(IntPtr display, X11WindowInfo window, string e)
{
if (window == null)
throw new ArgumentNullException("window");
@ -241,15 +244,17 @@ namespace OpenTK.Platform.X11
if (window.Display != display)
throw new InvalidOperationException();
string extensions = null;
using (new XLock(display))
if (String.IsNullOrEmpty(extensions))
{
extensions = Glx.QueryExtensionsString(display, window.Screen);
using (new XLock(display))
{
extensions = Glx.QueryExtensionsString(display, window.Screen);
}
}
return !String.IsNullOrEmpty(extensions) && extensions.Contains(e);
}
static bool SupportsCreateContextAttribs(IntPtr display, X11WindowInfo window)
bool SupportsCreateContextAttribs(IntPtr display, X11WindowInfo window)
{
return
SupportsExtension(display, window, "GLX_ARB_create_context") &&
@ -354,29 +359,40 @@ namespace OpenTK.Platform.X11
{
get
{
if (vsync_supported)
return swap_interval;
else
return 0;
using (new XLock(display))
{
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
return 0;
}
}
set
{
if (vsync_supported)
if (value < 0 && !vsync_tear_supported)
{
if (value < 0 && !vsync_tear_supported)
{
value = 1;
}
ErrorCode error_code = 0;
using (new XLock(Display))
error_code = Glx.Sgi.SwapInterval(value);
if (error_code == X11.ErrorCode.NO_ERROR)
swap_interval = value;
else
Debug.Print("VSync = {0} failed, error code: {1}.", value, error_code);
value = 1;
}
ErrorCode error_code = 0;
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);
}
if (error_code == X11.ErrorCode.NO_ERROR)
sgi_swap_interval = value;
else
Debug.Print("VSync = {0} failed, error code: {1}.", value, error_code);
}
}
@ -386,12 +402,23 @@ namespace OpenTK.Platform.X11
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") &&
Glx.SupportsFunction("glXSwapIntervalSGI");
Debug.Print("Context supports vsync: {0}.",
vsync_ext_supported || vsync_mesa_supported || vsync_ext_supported);
vsync_tear_supported =
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();
}

View file

@ -45,7 +45,7 @@ namespace OpenTK.Platform.X11
/// Drives GameWindow on X11.
/// This class supports OpenTK, and is not intended for use by OpenTK programs.
/// </summary>
internal sealed class X11GLNative : INativeWindow, IDisposable
internal sealed class X11GLNative : NativeWindowBase
{
// TODO: Disable screensaver.
// TODO: What happens if we can't disable decorations through motif?
@ -57,11 +57,6 @@ namespace OpenTK.Platform.X11
X11WindowInfo window = new X11WindowInfo();
// Legacy input support
X11Input driver;
KeyboardDevice keyboard;
MouseDevice mouse;
// 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
// are not ICCM compliant, but may support MOTIF hints.
@ -116,6 +111,13 @@ namespace OpenTK.Platform.X11
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;
IntPtr cursorHandle;
bool cursor_visible = true;
@ -124,14 +126,14 @@ namespace OpenTK.Platform.X11
// Keyboard input
readonly byte[] ascii = new byte[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;
public static bool MouseWarpActive = false;
readonly bool xi2_supported;
readonly int xi2_opcode;
#endregion
#region Constructors
@ -224,15 +226,26 @@ namespace OpenTK.Platform.X11
e.ConfigureEvent.height = height;
RefreshWindowBounds(ref e);
driver = new X11Input(window);
keyboard = driver.Keyboard[0];
mouse = driver.Mouse[0];
EmptyCursor = CreateEmptyCursor(window);
Debug.WriteLine(String.Format("X11GLNative window created successfully (id: {0}).", Handle));
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;
}
@ -733,7 +746,7 @@ namespace OpenTK.Platform.X11
if (Location != new_location)
{
bounds.Location = new_location;
Move(this, EventArgs.Empty);
OnMove(EventArgs.Empty);
}
// Note: width and height denote the internal (client) size.
@ -744,9 +757,15 @@ namespace OpenTK.Platform.X11
if (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);
@ -768,25 +787,15 @@ namespace OpenTK.Platform.X11
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
#region INativeWindow Members
#region ProcessEvents
public void ProcessEvents()
public override void ProcessEvents()
{
base.ProcessEvents();
// Process all pending events
while (Exists && window != null)
{
@ -805,7 +814,7 @@ namespace OpenTK.Platform.X11
bool previous_visible = visible;
visible = true;
if (visible != previous_visible)
VisibleChanged(this, EventArgs.Empty);
OnVisibleChanged(EventArgs.Empty);
}
return;
@ -814,7 +823,7 @@ namespace OpenTK.Platform.X11
bool previous_visible = visible;
visible = false;
if (visible != previous_visible)
VisibleChanged(this, EventArgs.Empty);
OnVisibleChanged(EventArgs.Empty);
}
break;
@ -827,7 +836,7 @@ namespace OpenTK.Platform.X11
{
Debug.WriteLine("Exit message received.");
CancelEventArgs ce = new CancelEventArgs();
Closing(this, ce);
OnClosing(ce);
if (!ce.Cancel)
{
@ -848,7 +857,7 @@ namespace OpenTK.Platform.X11
Debug.WriteLine("Window destroyed");
exists = false;
Closed(this, EventArgs.Empty);
OnClosed(EventArgs.Empty);
return;
@ -860,26 +869,18 @@ namespace OpenTK.Platform.X11
case XEventName.KeyRelease:
bool pressed = e.type == XEventName.KeyPress;
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)
{
// Raise KeyDown event
KeyDownEventArgs.Key = key;
KeyDownEventArgs.ScanCode = (uint)e.KeyEvent.keycode;
KeyDownEventArgs.Modifiers = keyboard.GetModifiers();
KeyDown(this, KeyDownEventArgs);
bool is_repeat = KeyboardState[key];
OnKeyDown(key, is_repeat);
}
else
{
// Raise KeyUp event
KeyUpEventArgs.Key = key;
KeyUpEventArgs.ScanCode = (uint)e.KeyEvent.keycode;
KeyUpEventArgs.Modifiers = keyboard.GetModifiers();
KeyUp(this, KeyUpEventArgs);
OnKeyUp(key);
}
if (pressed)
@ -895,8 +896,7 @@ namespace OpenTK.Platform.X11
{
if (!Char.IsControl(chars[i]))
{
KPEventArgs.KeyChar = chars[i];
KeyPress(this, KPEventArgs);
OnKeyPress(chars[i]);
}
}
}
@ -910,7 +910,7 @@ namespace OpenTK.Platform.X11
// to the dead center of the window. Fortunately, this situation
// is very very uncommon. Todo: Can this be remedied?
int x = e.MotionEvent.x;
int y =e.MotionEvent.y;
int y = e.MotionEvent.y;
// TODO: Have offset as a stored field, only update it when the window moves
// The middle point cannot be the average of the Bounds.left/right/top/bottom,
// because these fields take into account window decoration (borders, etc),
@ -929,10 +929,9 @@ namespace OpenTK.Platform.X11
}
else if (!CursorVisible)
{
SetMouseClamped(mouse,
mouse.X + x - mouse_rel_x,
mouse.Y + y - mouse_rel_y,
0, 0, Width, Height);
OnMouseMove(
MathHelper.Clamp(MouseState.X + x - mouse_rel_x, 0, Width),
MathHelper.Clamp(MouseState.Y + y - mouse_rel_y, 0, Height));
mouse_rel_x = x;
mouse_rel_y = y;
@ -942,16 +941,42 @@ namespace OpenTK.Platform.X11
}
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_y = y;
}
break;
}
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:
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;
case XEventName.FocusIn:
@ -959,7 +984,7 @@ namespace OpenTK.Platform.X11
bool previous_focus = has_focus;
has_focus = true;
if (has_focus != previous_focus)
FocusedChanged(this, EventArgs.Empty);
OnFocusedChanged(EventArgs.Empty);
}
break;
@ -968,19 +993,19 @@ namespace OpenTK.Platform.X11
bool previous_focus = has_focus;
has_focus = false;
if (has_focus != previous_focus)
FocusedChanged(this, EventArgs.Empty);
OnFocusedChanged(EventArgs.Empty);
}
break;
case XEventName.LeaveNotify:
if (CursorVisible)
{
MouseLeave(this, EventArgs.Empty);
OnMouseLeave(EventArgs.Empty);
}
break;
case XEventName.EnterNotify:
MouseEnter(this, EventArgs.Empty);
OnMouseEnter(EventArgs.Empty);
break;
case XEventName.MappingNotify:
@ -995,7 +1020,7 @@ namespace OpenTK.Platform.X11
case XEventName.PropertyNotify:
if (e.PropertyEvent.atom == _atom_net_wm_state)
{
WindowStateChanged(this, EventArgs.Empty);
OnWindowStateChanged(EventArgs.Empty);
}
//if (e.PropertyEvent.atom == _atom_net_frame_extents)
@ -1015,7 +1040,7 @@ namespace OpenTK.Platform.X11
#region Bounds
public Rectangle Bounds
public override Rectangle Bounds
{
get
{
@ -1061,50 +1086,18 @@ namespace OpenTK.Platform.X11
#endregion
#region Location
#region ClientSize
public Point Location
{
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
public override Size ClientSize
{
get
{
if (client_rectangle.Width == 0)
client_rectangle.Width = 1;
if (client_rectangle.Height == 0)
client_rectangle.Height = 1;
return client_rectangle;
return client_rectangle.Size;
}
set
{
using (new XLock(window.Display))
{
Functions.XMoveWindow(window.Display, window.Handle,
value.X, value.Y);
Functions.XResizeWindow(window.Display, window.Handle,
value.Width, value.Height);
}
@ -1114,65 +1107,9 @@ namespace OpenTK.Platform.X11
#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
public Icon Icon
public override Icon Icon
{
get
{
@ -1238,7 +1175,7 @@ namespace OpenTK.Platform.X11
}
icon = value;
IconChanged(this, EventArgs.Empty);
OnIconChanged(EventArgs.Empty);
}
}
@ -1246,7 +1183,7 @@ namespace OpenTK.Platform.X11
#region Focused
public bool Focused
public override bool Focused
{
get
{
@ -1258,7 +1195,7 @@ namespace OpenTK.Platform.X11
#region WindowState
public OpenTK.WindowState WindowState
public override OpenTK.WindowState WindowState
{
get
{
@ -1319,75 +1256,105 @@ namespace OpenTK.Platform.X11
{
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)
return;
Debug.Print("GameWindow {0} changing WindowState from {1} to {2}.", window.Handle.ToString(),
current_state.ToString(), value.ToString());
current_state.ToString(), value.ToString());
using (new XLock(window.Display))
// 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)
{
// Reset the current window state
if (current_state == OpenTK.WindowState.Minimized)
Functions.XMapWindow(window.Display, window.Handle);
else if (current_state == OpenTK.WindowState.Fullscreen)
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_remove,
_atom_net_wm_state_fullscreen,
IntPtr.Zero);
else if (current_state == OpenTK.WindowState.Maximized)
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_toggle,
_atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical);
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)
{
temporary_resizable = true;
WindowBorder = WindowBorder.Resizable;
}
using (new XLock(window.Display))
{
switch (value)
// 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))
{
switch (current_state)
{
case OpenTK.WindowState.Normal:
Functions.XRaiseWindow(window.Display, window.Handle);
break;
case OpenTK.WindowState.Maximized:
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical);
Functions.XRaiseWindow(window.Display, window.Handle);
break;
case OpenTK.WindowState.Minimized:
// Todo: multiscreen support
Functions.XIconifyWindow(window.Display, window.Handle, window.Screen);
Functions.XMapWindow(window.Display, window.Handle);
break;
case OpenTK.WindowState.Fullscreen:
//_previous_window_border = this.WindowBorder;
//this.WindowBorder = WindowBorder.Hidden;
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_net_wm_state_fullscreen, IntPtr.Zero);
Functions.XRaiseWindow(window.Display, window.Handle);
Functions.SendNetWMMessage(window,
_atom_net_wm_state,
_atom_remove,
_atom_net_wm_state_fullscreen,
IntPtr.Zero);
break;
case OpenTK.WindowState.Maximized:
Functions.SendNetWMMessage(window,
_atom_net_wm_state,
_atom_toggle,
_atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical);
break;
}
}
}
}
if (temporary_resizable)
WindowBorder = previous_state;
void ChangeWindowState(OpenTK.WindowState value)
{
using (new XLock(window.Display))
{
switch (value)
{
case OpenTK.WindowState.Normal:
Functions.XRaiseWindow(window.Display, window.Handle);
ChangeWindowBorder(_previous_window_border,
_previous_window_size.Width, _previous_window_size.Height);
break;
ProcessEvents();
case OpenTK.WindowState.Maximized:
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_net_wm_state_maximized_horizontal,
_atom_net_wm_state_maximized_vertical);
Functions.XRaiseWindow(window.Display, window.Handle);
break;
case OpenTK.WindowState.Minimized:
Functions.XIconifyWindow(window.Display, window.Handle, window.Screen);
break;
case OpenTK.WindowState.Fullscreen:
Functions.SendNetWMMessage(window, _atom_net_wm_state, _atom_add,
_atom_net_wm_state_fullscreen, IntPtr.Zero);
Functions.XRaiseWindow(window.Display, window.Handle);
break;
}
}
}
@ -1395,77 +1362,76 @@ namespace OpenTK.Platform.X11
#region WindowBorder
public OpenTK.WindowBorder WindowBorder
public override OpenTK.WindowBorder WindowBorder
{
get
{
if (IsWindowBorderHidden)
if (IsWindowBorderHidden || WindowState == OpenTK.WindowState.Fullscreen)
return WindowBorder.Hidden;
if (IsWindowBorderResizable)
return WindowBorder.Resizable;
else
else if (!IsWindowBorderResizable)
return WindowBorder.Fixed;
else if (WindowState == OpenTK.WindowState.Maximized)
return _previous_window_border;
else
return WindowBorder.Resizable;
}
set
{
if (WindowBorder == value)
return;
if (WindowBorder == WindowBorder.Hidden)
EnableWindowDecorations();
switch (value)
// 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)
{
case WindowBorder.Fixed:
Debug.Print("Making WindowBorder fixed.");
SetWindowMinMax((short)Width, (short)Height, (short)Width, (short)Height);
break;
case WindowBorder.Resizable:
Debug.Print("Making WindowBorder resizable.");
SetWindowMinMax(_min_width, _min_height, -1, -1);
break;
case WindowBorder.Hidden:
Debug.Print("Making WindowBorder hidden.");
DisableWindowDecorations();
break;
_previous_window_border = value;
return;
}
WindowBorderChanged(this, EventArgs.Empty);
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)
EnableWindowDecorations();
switch (value)
{
case WindowBorder.Fixed:
Debug.Print("Making WindowBorder fixed.");
SetWindowMinMax((short)width, (short)height, (short)width, (short)height);
break;
case WindowBorder.Resizable:
Debug.Print("Making WindowBorder resizable.");
SetWindowMinMax(_min_width, _min_height, -1, -1);
break;
case 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();
break;
}
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
#region Cursor
public MouseCursor Cursor
public override MouseCursor Cursor
{
get
{
@ -1505,7 +1471,7 @@ namespace OpenTK.Platform.X11
#region CursorVisible
public bool CursorVisible
public override bool CursorVisible
{
get { return cursor_visible; }
set
@ -1535,24 +1501,12 @@ namespace OpenTK.Platform.X11
#region --- INativeGLWindow Members ---
#region public IInputDriver InputDriver
public IInputDriver InputDriver
{
get
{
return driver;
}
}
#endregion
#region public bool Exists
/// <summary>
/// Returns true if a render window/context exists.
/// </summary>
public bool Exists
public override bool Exists
{
get { return exists; }
}
@ -1586,7 +1540,7 @@ namespace OpenTK.Platform.X11
/// TODO: Use atoms for this property.
/// Gets or sets the GameWindow title.
/// </summary>
public string Title
public override string Title
{
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
public bool Visible
public override bool Visible
{
get
{
@ -1647,14 +1601,14 @@ namespace OpenTK.Platform.X11
#region public IWindowInfo WindowInfo
public IWindowInfo WindowInfo
public override IWindowInfo WindowInfo
{
get { return window; }
}
#endregion
public void Close() { Exit(); }
public override void Close() { Exit(); }
#region public void Exit()
@ -1691,7 +1645,7 @@ namespace OpenTK.Platform.X11
#region PointToClient
public Point PointToClient(Point point)
public override Point PointToClient(Point point)
{
int ox, oy;
IntPtr child;
@ -1711,7 +1665,7 @@ namespace OpenTK.Platform.X11
#region PointToScreen
public Point PointToScreen(Point point)
public override Point PointToScreen(Point point)
{
int ox, oy;
IntPtr child;
@ -1733,13 +1687,7 @@ namespace OpenTK.Platform.X11
#region IDisposable Members
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool manuallyCalled)
protected override void Dispose(bool manuallyCalled)
{
if (!disposed)
{
@ -1775,11 +1723,6 @@ namespace OpenTK.Platform.X11
}
}
~X11GLNative()
{
this.Dispose(false);
}
#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;
}
}
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>();
Dictionary<int, int> rawids = new Dictionary<int, int>(); // maps raw ids to mouse ids
internal readonly X11WindowInfo window;
static int XIOpCode;
internal static int XIOpCode { get; private set; }
static bool supported;
static readonly Functions.EventPredicate PredicateImpl = IsEventValid;
readonly IntPtr Predicate = Marshal.GetFunctionPointerForDelegate(PredicateImpl);
@ -204,8 +205,8 @@ namespace OpenTK.Platform.X11
case 1: state.EnableBit((int)MouseButton.Left); break;
case 2: state.EnableBit((int)MouseButton.Middle); break;
case 3: state.EnableBit((int)MouseButton.Right); break;
case 4: state.WheelPrecise++; break;
case 5: state.WheelPrecise--; break;
case 4: state.SetScrollRelative(0, 1); break;
case 5: state.SetScrollRelative(0, -1); break;
case 6: state.EnableBit((int)MouseButton.Button1); break;
case 7: state.EnableBit((int)MouseButton.Button2); break;
case 8: state.EnableBit((int)MouseButton.Button3); break;