diff --git a/Source/Examples/OpenTK/Test/GameWindowStates.cs b/Source/Examples/OpenTK/Test/GameWindowStates.cs index 2e5ce406..e75f8977 100644 --- a/Source/Examples/OpenTK/Test/GameWindowStates.cs +++ b/Source/Examples/OpenTK/Test/GameWindowStates.cs @@ -26,6 +26,10 @@ namespace Examples.Tests 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; @@ -57,6 +61,7 @@ namespace Examples.Tests MouseLeave += delegate { mouse_in_window = false; }; Mouse.Move += MouseMoveHandler; + Mouse.WheelChanged += MouseWheelHandler; Mouse.ButtonDown += MouseButtonHandler; Mouse.ButtonUp += MouseButtonHandler; } @@ -119,6 +124,10 @@ namespace Examples.Tests 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) @@ -127,6 +136,21 @@ namespace Examples.Tests { 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) @@ -201,6 +225,40 @@ namespace Examples.Tests 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 joysticks, int line) { line++; @@ -267,7 +325,8 @@ 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 = DrawMouseDevice(gfx, line); // Timing information line++; diff --git a/Source/OpenTK/Input/MouseDevice.cs b/Source/OpenTK/Input/MouseDevice.cs index 2e922ff3..ebcd7f74 100644 --- a/Source/OpenTK/Input/MouseDevice.cs +++ b/Source/OpenTK/Input/MouseDevice.cs @@ -362,6 +362,24 @@ namespace OpenTK.Input #endregion } + /// + /// Represents a mouse wheel. + /// + public sealed class MouseWheel + { + /// + /// Gets the X offset of the wheel. + /// + /// The x. + public float X { get; internal set; } + + /// + /// Gets the Y offset of the wheel. + /// + /// The y. + public float Y { get; internal set; } + } + #region Event Arguments /// @@ -390,6 +408,7 @@ namespace OpenTK.Input /// public MouseEventArgs() { + Wheel = new MouseWheel(); } /// @@ -416,7 +435,7 @@ namespace OpenTK.Input #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(); @@ -433,7 +452,7 @@ namespace OpenTK.Input } } - protected internal ButtonState GetButton(MouseButton button) + internal ButtonState GetButton(MouseButton button) { if (button < 0 || button > MouseButton.LastButton) throw new ArgumentOutOfRangeException(); @@ -458,21 +477,9 @@ namespace OpenTK.Input public int Y { get { return y; } internal set { y = value; } } /// - /// Gets the offset of the horizontal wheel, if one exists. + /// Gets the status of the mouse wheel. /// - public float WheelX { get; internal set; } - - /// - /// Gets the offset of the vertical wheel, if one exists. - /// - public float WheelY { get; internal set; } - - /// - /// Gets the offset of the vertical wheel, if one exists. - /// This is an alias to - /// - /// The wheel. - public float Wheel { get { return WheelY; } internal set { WheelY = value; } } + public MouseWheel Wheel { get; private set; } /// /// Gets the of the left mouse button. @@ -705,7 +712,7 @@ namespace OpenTK.Input public MouseWheelEventArgs(int x, int y, int value, int delta) : base(x, y) { - WheelY = value; + Wheel.Y = value; this.delta = delta; } @@ -726,7 +733,7 @@ namespace OpenTK.Input /// Gets the value of the wheel in integer units. /// To support high-precision mice, it is recommended to use instead. /// - public int Value { get { return (int)Math.Round(WheelY, MidpointRounding.AwayFromZero); } } + public int Value { get { return (int)Math.Round(Wheel.Y, MidpointRounding.AwayFromZero); } } /// /// Gets the change in value of the wheel for this event in integer units. @@ -737,7 +744,7 @@ namespace OpenTK.Input /// /// Gets the precise value of the wheel in floating-point units. /// - public float ValuePrecise { get { return WheelY; } internal set { WheelY = value; } } + public float ValuePrecise { get { return Wheel.Y; } internal set { Wheel.Y = value; } } /// /// Gets the precise change in value of the wheel for this event in floating-point units. diff --git a/Source/OpenTK/Platform/LegacyInputDriver.cs b/Source/OpenTK/Platform/LegacyInputDriver.cs index 290f6321..96d0a02a 100644 --- a/Source/OpenTK/Platform/LegacyInputDriver.cs +++ b/Source/OpenTK/Platform/LegacyInputDriver.cs @@ -78,7 +78,7 @@ namespace OpenTK.Platform window.MouseWheel += (sender, e) => { - mouse.WheelPrecise = e.WheelY; + mouse.WheelPrecise = e.Wheel.Y; }; // Hook keyboard events diff --git a/Source/OpenTK/Platform/NativeWindowBase.cs b/Source/OpenTK/Platform/NativeWindowBase.cs index ed7f32ea..64e6bee0 100644 --- a/Source/OpenTK/Platform/NativeWindowBase.cs +++ b/Source/OpenTK/Platform/NativeWindowBase.cs @@ -49,6 +49,10 @@ namespace OpenTK.Platform 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); diff --git a/Source/OpenTK/Platform/SDL2/Sdl2Mouse.cs b/Source/OpenTK/Platform/SDL2/Sdl2Mouse.cs index ffd8cc38..887ad7af 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2Mouse.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2Mouse.cs @@ -33,28 +33,18 @@ using OpenTK.Input; namespace OpenTK.Platform.SDL2 { - class Sdl2Mouse : IMouseDriver2, IMouseDriver + class Sdl2Mouse : IMouseDriver2 { MouseState state; - readonly List mice = - new List(); - readonly IList 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) { @@ -98,33 +88,18 @@ namespace OpenTK.Platform.SDL2 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 Mouse - { - get - { - return mice_readonly; - } } #endregion diff --git a/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs b/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs index f30ba51d..8c3367fd 100644 --- a/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs +++ b/Source/OpenTK/Platform/SDL2/Sdl2NativeWindow.cs @@ -175,7 +175,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; @@ -183,7 +183,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; @@ -191,7 +191,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; @@ -209,9 +209,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. @@ -220,6 +220,23 @@ namespace OpenTK.Platform.SDL2 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) @@ -273,16 +290,32 @@ namespace OpenTK.Platform.SDL2 } } - 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)); + //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 ProcessWheelEvent(Sdl2NativeWindow window, Event ev) + static void SetMouseButtons(MouseEventArgs e, ButtonFlags buttons) { - //window.mouse.Wheel += ev.wheel.y; + 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 ProcessMouseWheelEvent(Sdl2NativeWindow window, MouseWheelEvent ev) + { + var e = window.MouseWheelArgs; + e.Wheel.Y = ev.Y; + e.Wheel.X = ev.X; + window.OnMouseWheel(e); } static void ProcessWindowEvent(Sdl2NativeWindow window, WindowEvent e) diff --git a/Source/OpenTK/Platform/Windows/API.cs b/Source/OpenTK/Platform/Windows/API.cs index 454d2aa0..3a0fd548 100644 --- a/Source/OpenTK/Platform/Windows/API.cs +++ b/Source/OpenTK/Platform/Windows/API.cs @@ -4197,7 +4197,6 @@ namespace OpenTK.Platform.Windows MBUTTONUP = 0x0208, MBUTTONDBLCLK = 0x0209, MOUSEWHEEL = 0x020A, - MOUSELAST = 0x020D, /// /// Windows 2000 and higher only. /// @@ -4210,6 +4209,10 @@ namespace OpenTK.Platform.Windows /// Windows 2000 and higher only. /// XBUTTONDBLCLK = 0x020D, + /// + /// Windows Vista and higher only. + /// + MOUSEHWHEEL = 0x020E, PARENTNOTIFY = 0x0210, ENTERMENULOOP = 0x0211, EXITMENULOOP = 0x0212, diff --git a/Source/OpenTK/Platform/Windows/WinGLNative.cs b/Source/OpenTK/Platform/Windows/WinGLNative.cs index 4e8f7328..da560894 100644 --- a/Source/OpenTK/Platform/Windows/WinGLNative.cs +++ b/Source/OpenTK/Platform/Windows/WinGLNative.cs @@ -506,7 +506,15 @@ namespace OpenTK.Platform.Windows { // 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); } @@ -729,6 +737,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;