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 borderless_maximized_window_state = false; // Hack to get maximized mode with hidden border (not normally possible).
bool focused; bool focused;
bool mouse_outside_window = true; bool mouse_outside_window = true;
int mouse_capture_count = 0;
int mouse_last_timestamp = 0; int mouse_last_timestamp = 0;
bool invisible_since_creation; // Set by WindowsMessage.CREATE and consumed by Visible = true (calls BringWindowToFront). 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. 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; 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) void HandleChar(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
char c; char c;
@ -399,13 +408,41 @@ namespace OpenTK.Platform.Windows
} }
void HandleMouseMove(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleMouseMove(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
unsafe
{ {
Point point = new Point( Point point = new Point(
(short)((uint)lParam.ToInt32() & 0x0000FFFF), (short)((uint)lParam.ToInt32() & 0x0000FFFF),
(short)(((uint)lParam.ToInt32() & 0xFFFF0000) >> 16)); (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 // GetMouseMovePointsEx works with screen coordinates
Point screenPoint = point; Point screenPoint = point;
Functions.ClientToScreen(handle, ref screenPoint); Functions.ClientToScreen(handle, ref screenPoint);
@ -479,25 +516,19 @@ namespace OpenTK.Platform.Windows
} }
mouse_last_timestamp = timestamp; 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) 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_outside_window = true;
// Mouse tracking is disabled automatically by the OS // Mouse tracking is disabled automatically by the OS
OnMouseLeave(EventArgs.Empty); OnMouseLeave(EventArgs.Empty);
} }
}
void HandleMouseWheel(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleMouseWheel(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
@ -515,25 +546,25 @@ namespace OpenTK.Platform.Windows
void HandleLButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleLButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.SetCapture(window.Handle); SetCapture();
OnMouseDown(MouseButton.Left); OnMouseDown(MouseButton.Left);
} }
void HandleMButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleMButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.SetCapture(window.Handle); SetCapture();
OnMouseDown(MouseButton.Middle); OnMouseDown(MouseButton.Middle);
} }
void HandleRButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleRButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.SetCapture(window.Handle); SetCapture();
OnMouseDown(MouseButton.Right); OnMouseDown(MouseButton.Right);
} }
void HandleXButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleXButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.SetCapture(window.Handle); SetCapture();
MouseButton button = MouseButton button =
((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ? ((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2; MouseButton.Button1 : MouseButton.Button2;
@ -542,25 +573,25 @@ namespace OpenTK.Platform.Windows
void HandleLButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleLButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.ReleaseCapture(); ReleaseCapture();
OnMouseUp(MouseButton.Left); OnMouseUp(MouseButton.Left);
} }
void HandleMButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleMButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.ReleaseCapture(); ReleaseCapture();
OnMouseUp(MouseButton.Middle); OnMouseUp(MouseButton.Middle);
} }
void HandleRButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleRButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.ReleaseCapture(); ReleaseCapture();
OnMouseUp(MouseButton.Right); OnMouseUp(MouseButton.Right);
} }
void HandleXButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) void HandleXButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{ {
Functions.ReleaseCapture(); ReleaseCapture();
MouseButton button = MouseButton button =
((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ? ((wParam.ToInt32() & 0xFFFF0000) >> 16) == 1 ?
MouseButton.Button1 : MouseButton.Button2; MouseButton.Button1 : MouseButton.Button2;
@ -694,6 +725,10 @@ namespace OpenTK.Platform.Windows
result = HandleSetCursor(handle, message, wParam, lParam); result = HandleSetCursor(handle, message, wParam, lParam);
break; break;
case WindowMessage.CAPTURECHANGED:
HandleCaptureChanged(handle, message, wParam, lParam);
break;
#endregion #endregion
#region Input events #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() private void EnableMouseTracking()
{ {
TrackMouseEventStructure me = new TrackMouseEventStructure(); TrackMouseEventStructure me = new TrackMouseEventStructure();