bool mouse_in_window = false;
bool viewport_changed = true;
+ // mouse information
+ Vector4 mouse_pos;
+ int mouse_buttons;
+
// time drift
Stopwatch watch = new Stopwatch();
double update_time, render_time;
MouseLeave += delegate { mouse_in_window = false; };
Mouse.Move += MouseMoveHandler;
+ Mouse.WheelChanged += MouseWheelHandler;
Mouse.ButtonDown += MouseButtonHandler;
Mouse.ButtonUp += MouseButtonHandler;
}
void MouseMoveHandler(object sender, MouseMoveEventArgs e)
{
+ mouse_pos.X = e.X;
+ mouse_pos.Y = e.Y;
+ mouse_pos.Z = e.Wheel.X;
+ mouse_pos.W = e.Wheel.Y;
}
void MouseButtonHandler(object sender, MouseButtonEventArgs e)
{
CursorVisible = false;
}
+
+ if (e.IsPressed)
+ {
+ mouse_buttons |= 1 << (int)e.Button;
+ }
+ else
+ {
+ mouse_buttons &= ~(1 << (int)e.Button);
+ }
+ }
+
+ void MouseWheelHandler(object sender, MouseWheelEventArgs e)
+ {
+ mouse_pos.Z += e.Wheel.Y;
+ mouse_pos.W += e.Wheel.X;
}
static int Clamp(int val, int min, int max)
return line;
}
+ int DrawMouseDevice(Graphics gfx, int line)
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append("MouseDevice: ");
+ sb.Append(new Vector3(Mouse.X, Mouse.Y, Mouse.Wheel));
+ sb.Append(" ");
+ 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("Mouse events: ");
+ sb.Append(mouse_pos);
+ sb.Append(" ");
+ for (var i = MouseButton.Left; i < MouseButton.LastButton; i++)
+ {
+ if ((mouse_buttons & (1 << (int)i)) != 0)
+ {
+ sb.Append(i);
+ sb.Append(" ");
+ }
+ }
+ sb.AppendLine();
+ DrawString(gfx, sb.ToString(), line++);
+ return line;
+ }
+
static int DrawLegacyJoysticks(Graphics gfx, IList<JoystickDevice> joysticks, int line)
{
line++;
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 = DrawMouseDevice(gfx, line);
// Timing information
line++;
#endregion
}
+ /// <summary>
+ /// Represents a mouse wheel.
+ /// </summary>
+ public sealed class MouseWheel
+ {
+ /// <summary>
+ /// Gets the X offset of the wheel.
+ /// </summary>
+ /// <value>The x.</value>
+ public float X { get; internal set; }
+
+ /// <summary>
+ /// Gets the Y offset of the wheel.
+ /// </summary>
+ /// <value>The y.</value>
+ public float Y { get; internal set; }
+ }
+
#region Event Arguments
/// <summary>
/// </summary>
public MouseEventArgs()
{
+ Wheel = new MouseWheel();
}
/// <summary>
#region Protected Members
- protected internal void SetButton(MouseButton button, ButtonState state)
+ internal void SetButton(MouseButton button, ButtonState state)
{
if (button < 0 || button > MouseButton.LastButton)
throw new ArgumentOutOfRangeException();
}
}
- protected internal ButtonState GetButton(MouseButton button)
+ internal ButtonState GetButton(MouseButton button)
{
if (button < 0 || button > MouseButton.LastButton)
throw new ArgumentOutOfRangeException();
public int Y { get { return y; } internal set { y = value; } }
/// <summary>
- /// Gets the offset of the horizontal wheel, if one exists.
- /// </summary>
- public float WheelX { get; internal set; }
-
- /// <summary>
- /// Gets the offset of the vertical wheel, if one exists.
- /// </summary>
- public float WheelY { get; internal set; }
-
- /// <summary>
- /// Gets the offset of the vertical wheel, if one exists.
- /// This is an alias to <see cref="MouseEventArgs.WheelY"/>
+ /// Gets the status of the mouse wheel.
/// </summary>
- /// <value>The wheel.</value>
- public float Wheel { get { return WheelY; } internal set { WheelY = value; } }
+ public MouseWheel Wheel { get; private set; }
/// <summary>
/// Gets the <see cref="ButtonState"/> of the left mouse button.
public MouseWheelEventArgs(int x, int y, int value, int delta)
: base(x, y)
{
- WheelY = value;
+ Wheel.Y = value;
this.delta = delta;
}
/// 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(WheelY, MidpointRounding.AwayFromZero); } }
+ public int Value { get { return (int)Math.Round(Wheel.Y, MidpointRounding.AwayFromZero); } }
/// <summary>
/// Gets the change in value of the wheel for this event in integer units.
/// <summary>
/// Gets the precise value of the wheel in floating-point units.
/// </summary>
- public float ValuePrecise { get { return WheelY; } internal set { WheelY = value; } }
+ public float ValuePrecise { get { return Wheel.Y; } internal set { Wheel.Y = value; } }
/// <summary>
/// Gets the precise change in value of the wheel for this event in floating-point units.
window.MouseWheel += (sender, e) =>
{
- mouse.WheelPrecise = e.WheelY;
+ mouse.WheelPrecise = e.Wheel.Y;
};
// Hook keyboard events
readonly protected KeyboardKeyEventArgs KeyUpArgs = new KeyboardKeyEventArgs();
readonly protected 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();
+
internal NativeWindowBase()
{
LegacyInputDriver = new LegacyInputDriver(this);
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)
{
public void ProcessWheelEvent(MouseWheelEvent wheel)
{
state.WheelPrecise += wheel.Y;
- mice[0].WheelPrecise += 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
case EventType.MOUSEBUTTONUP:
if (windows.TryGetValue(ev.Button.WindowID, out window))
{
- ProcessButtonEvent(window, ev);
+ ProcessMouseButtonEvent(window, ev.Button);
processed = true;
}
break;
case EventType.MOUSEMOTION:
if (windows.TryGetValue(ev.Motion.WindowID, out window))
{
- ProcessMotionEvent(window, ev);
+ ProcessMouseMotionEvent(window, ev.Motion);
processed = true;
}
break;
case EventType.MOUSEWHEEL:
if (windows.TryGetValue(ev.Wheel.WindowID, out window))
{
- ProcessWheelEvent(window, ev);
+ ProcessMouseWheelEvent(window, ev.Wheel);
processed = true;
}
break;
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.
SDL.SetWindowGrab(window.window.Handle,
button_pressed ? true : false);
}
+
+ var e = button_pressed ? window.MouseDownArgs : window.MouseUpArgs;
+ e.Button = Sdl2Mouse.TranslateButton(ev.Button);
+ e.IsPressed = button_pressed;
+ e.X = ev.X;
+ e.Y = ev.Y;
+ e.Wheel.X = window.MouseWheelArgs.Wheel.X;
+ e.Wheel.Y = window.MouseWheelArgs.Wheel.Y;
+
+ if (button_pressed)
+ {
+ window.OnMouseDown(e);
+ }
+ else
+ {
+ window.OnMouseUp(e);
+ }
}
static void ProcessKeyEvent(Sdl2NativeWindow window, Event ev)
}
}
- static void ProcessMotionEvent(Sdl2NativeWindow window, Event ev)
+ static void ProcessMouseMotionEvent(Sdl2NativeWindow window, MouseMotionEvent ev)
+ {
+ //float scale = window.ClientSize.Width / (float)window.Size.Width;
+ var e = window.MouseMoveArgs;
+ e.X = ev.X;
+ e.Y = ev.Y;
+ SetMouseButtons(e, ev.State);
+ window.OnMouseMove(e);
+ }
+
+ static void SetMouseButtons(MouseEventArgs e, ButtonFlags buttons)
{
- float scale = window.ClientSize.Width / (float)window.Size.Width;
- //window.mouse.Position = new Point(
- // (int)(ev.motion.x * scale), (int)(ev.motion.y * scale));
+ for (int i = 0; i < 5; i++)
+ {
+ // Note: OpenTK MouseButton is identical to SDL2 Button
+ bool pressed = ((int)buttons & (1 << i)) != 0;
+ e.SetButton((MouseButton)i, pressed ? ButtonState.Pressed : ButtonState.Released);
+ }
}
- static void ProcessWheelEvent(Sdl2NativeWindow window, Event ev)
+ static void ProcessMouseWheelEvent(Sdl2NativeWindow window, MouseWheelEvent ev)
{
- //window.mouse.Wheel += ev.wheel.y;
+ var e = window.MouseWheelArgs;
+ e.Wheel.Y = ev.Y;
+ e.Wheel.X = ev.X;
+ window.OnMouseWheel(e);
}
static void ProcessWindowEvent(Sdl2NativeWindow window, WindowEvent e)
MBUTTONUP = 0x0208,
MBUTTONDBLCLK = 0x0209,
MOUSEWHEEL = 0x020A,
- MOUSELAST = 0x020D,
/// <summary>
/// Windows 2000 and higher only.
/// </summary>
/// Windows 2000 and higher only.
/// </summary>
XBUTTONDBLCLK = 0x020D,
+ /// <summary>
+ /// Windows Vista and higher only.
+ /// </summary>
+ MOUSEHWHEEL = 0x020E,
PARENTNOTIFY = 0x0210,
ENTERMENULOOP = 0x0211,
EXITMENULOOP = 0x0212,
{
// This is due to inconsistent behavior of the WParam value on 64bit arch, whese
// wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000
- MouseWheelArgs.Wheel += ((long)wParam << 32 >> 48) / 120.0f;
+ MouseWheelArgs.Wheel.Y += ((long)wParam << 32 >> 48) / 120.0f;
+ OnMouseWheel(MouseWheelArgs);
+ }
+
+ 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
+ MouseWheelArgs.Wheel.X += ((long)wParam << 32 >> 48) / 120.0f;
OnMouseWheel(MouseWheelArgs);
}
HandleMouseWheel(handle, message, wParam, lParam);
break;
+ case WindowMessage.MOUSEHWHEEL:
+ HandleMouseHWheel(handle, message, wParam, lParam);
+ break;
+
case WindowMessage.LBUTTONDOWN:
HandleLButtonDown(handle, message, wParam, lParam);
break;