Merge pull request #302 from Frassle/mouse

[Win32] Fix spurious mouse enter and leave messages
This commit is contained in:
Fraser Waters 2015-10-17 23:24:33 +01:00
commit 0013b91f65

View file

@ -70,6 +70,7 @@ namespace OpenTK.Platform.Windows
bool borderless_maximized_window_state = false; // Hack to get maximized mode with hidden border (not normally possible).
bool focused;
bool mouse_outside_window = true;
int mouse_capture_count = 0;
int mouse_last_timestamp = 0;
bool invisible_since_creation; // Set by WindowsMessage.CREATE and consumed by Visible = true (calls BringWindowToFront).
int suppress_resize; // Used in WindowBorder and WindowState in order to avoid rapid, consecutive resize events.
@ -384,6 +385,14 @@ namespace OpenTK.Platform.Windows
return null;
}
private void HandleCaptureChanged(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
if (lParam != window.Handle)
{
mouse_capture_count = 0;
}
}
void HandleChar(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
char c;
@ -399,13 +408,41 @@ namespace OpenTK.Platform.Windows
}
void HandleMouseMove(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
unsafe
{
Point point = new Point(
(short)((uint)lParam.ToInt32() & 0x0000FFFF),
(short)(((uint)lParam.ToInt32() & 0xFFFF0000) >> 16));
if (mouse_capture_count > 0)
{
bool mouse_was_outside_window = mouse_outside_window;
mouse_outside_window = !ClientRectangle.Contains(point);
if (mouse_outside_window && !mouse_was_outside_window)
{
// Mouse leaving
// If we have mouse capture we ignore WM_MOUSELEAVE events, so
// have to manually call OnMouseLeave here.
// Mouse tracking is disabled automatically by the OS
OnMouseLeave(EventArgs.Empty);
}
else if (!mouse_outside_window && mouse_was_outside_window)
{
// Mouse entring
OnMouseEnter(EventArgs.Empty);
}
}
else if (/* !mouse_is_captured && */ mouse_outside_window)
{
// Once we receive a mouse move event, it means that the mouse has
// re-entered the window.
mouse_outside_window = false;
EnableMouseTracking();
OnMouseEnter(EventArgs.Empty);
}
unsafe
{
// GetMouseMovePointsEx works with screen coordinates
Point screenPoint = point;
Functions.ClientToScreen(handle, ref screenPoint);
@ -479,25 +516,19 @@ namespace OpenTK.Platform.Windows
}
mouse_last_timestamp = timestamp;
}
if (mouse_outside_window)
{
// Once we receive a mouse move event, it means that the mouse has
// re-entered the window.
mouse_outside_window = false;
EnableMouseTracking();
OnMouseEnter(EventArgs.Empty);
}
}
void HandleMouseLeave(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
// If the mouse is captured we get spurious MOUSELEAVE events.
// So ignore WM_MOUSELEAVE if capture count != 0.
if (mouse_capture_count == 0 )
{
mouse_outside_window = true;
// Mouse tracking is disabled automatically by the OS
OnMouseLeave(EventArgs.Empty);
}
}
void HandleMouseWheel(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
@ -515,25 +546,25 @@ namespace OpenTK.Platform.Windows
void HandleLButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.SetCapture(window.Handle);
SetCapture();
OnMouseDown(MouseButton.Left);
}
void HandleMButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.SetCapture(window.Handle);
SetCapture();
OnMouseDown(MouseButton.Middle);
}
void HandleRButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.SetCapture(window.Handle);
SetCapture();
OnMouseDown(MouseButton.Right);
}
void HandleXButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.SetCapture(window.Handle);
SetCapture();
MouseButton button =
((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2;
@ -542,25 +573,25 @@ namespace OpenTK.Platform.Windows
void HandleLButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.ReleaseCapture();
ReleaseCapture();
OnMouseUp(MouseButton.Left);
}
void HandleMButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.ReleaseCapture();
ReleaseCapture();
OnMouseUp(MouseButton.Middle);
}
void HandleRButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.ReleaseCapture();
ReleaseCapture();
OnMouseUp(MouseButton.Right);
}
void HandleXButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Functions.ReleaseCapture();
ReleaseCapture();
MouseButton button =
((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2;
@ -694,6 +725,10 @@ namespace OpenTK.Platform.Windows
result = HandleSetCursor(handle, message, wParam, lParam);
break;
case WindowMessage.CAPTURECHANGED:
HandleCaptureChanged(handle, message, wParam, lParam);
break;
#endregion
#region Input events
@ -794,6 +829,26 @@ namespace OpenTK.Platform.Windows
}
}
private void SetCapture()
{
if (mouse_capture_count == 0)
{
Functions.SetCapture(window.Handle);
}
mouse_capture_count++;
}
private void ReleaseCapture()
{
mouse_capture_count--;
if (mouse_capture_count == 0)
{
Functions.ReleaseCapture();
// Renable mouse tracking
EnableMouseTracking();
}
}
private void EnableMouseTracking()
{
TrackMouseEventStructure me = new TrackMouseEventStructure();