Merge remote-tracking branch 'frassle/issue76' into develop

This commit is contained in:
thefiddler 2014-04-01 09:39:48 +02:00
commit 74cff79d64
2 changed files with 171 additions and 4 deletions

View file

@ -371,6 +371,21 @@ namespace OpenTK.Platform.Windows
#endregion
#region GetMessageTime
/// <summary>
/// Retrieves the message time for the last message retrieved by the
/// GetMessage function. The time is a long integer that specifies the
/// elapsed time, in milliseconds, from the time the system was started
/// to the time the message was created (that is, placed in the thread's
/// message queue).
/// </summary>
/// <returns>The return value specifies the message time.</returns>
[DllImport("User32.dll")]
internal static extern int GetMessageTime();
#endregion
#region SendMessage
[DllImport("user32.dll", CharSet = CharSet.Auto)]
@ -1004,6 +1019,30 @@ namespace OpenTK.Platform.Windows
[DllImport("user32.dll")]
public static extern bool SetCursorPos(int X, int Y);
/// <summary>
/// Retrieves a history of up to 64 previous coordinates of the mouse or pen.
/// </summary>
/// <param name="cbSize">The size, in bytes, of the MouseMovePoint structure.</param>
/// <param name="pointsIn">
/// A pointer to a MOUSEMOVEPOINT structure containing valid mouse
/// coordinates (in screen coordinates). It may also contain a time
/// stamp.
/// </param>
/// <param name="pointsBufferOut">
/// A pointer to a buffer that will receive the points. It should be at
/// least cbSize * nBufPoints in size.
/// </param>
/// <param name="nBufPoints">The number of points to be retrieved.</param>
/// <param name="resolution">
/// The resolution desired. This parameter can GMMP_USE_DISPLAY_POINTS
/// or GMMP_USE_HIGH_RESOLUTION_POINTS.
/// </param>
/// <returns></returns>
[DllImport("user32", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
unsafe internal static extern int GetMouseMovePointsEx(
uint cbSize, MouseMovePoint* pointsIn,
MouseMovePoint* pointsBufferOut, int nBufPoints, uint resolution);
#region Async input
#region GetCursorPos
@ -1633,6 +1672,27 @@ namespace OpenTK.Platform.Windows
internal static readonly IntPtr MESSAGE_ONLY = new IntPtr(-3);
internal static readonly IntPtr HKEY_LOCAL_MACHINE = new IntPtr(unchecked((int)0x80000002));
// System Error Codes
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx
/// <summary>
/// The point passed to GetMouseMovePoints is not in the buffer.
/// </summary>
internal const int ERROR_POINT_NOT_FOUND = 1171;
/// <summary>
/// Retrieves the points using the display resolution.
/// </summary>
internal const int GMMP_USE_DISPLAY_POINTS = 1;
/// <summary>
/// Retrieves high resolution points. Points can range from zero to
/// 65,535 (0xFFFF) in both x and y coordinates. This is the resolution
/// provided by absolute coordinate pointing devices such as drawing
/// tablets.
/// </summary>
internal const int GMMP_USE_HIGH_RESOLUTION_POINTS = 2;
}
#endregion
@ -2917,6 +2977,36 @@ namespace OpenTK.Platform.Windows
#endregion
#region MouseMovePoint
/// <summary>
/// Contains information about the mouse's location in screen coordinates.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct MouseMovePoint
{
/// <summary>
/// The x-coordinate of the mouse.
/// </summary>
public int X;
/// <summary>
/// The y-coordinate of the mouse.
/// </summary>
public int Y;
/// <summary>
/// The time stamp of the mouse coordinate.
/// </summary>
public int Time;
/// <summary>
/// Additional information associated with this coordinate.
/// </summary>
public IntPtr ExtraInfo;
public static readonly int SizeInBytes = Marshal.SizeOf(default(MouseMovePoint));
}
#endregion
#endregion
#region --- Enums ---

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_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.
bool is_in_modal_loop; // set to true whenever we enter the modal resize/move event loop
@ -403,10 +404,86 @@ namespace OpenTK.Platform.Windows
void HandleMouseMove(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
{
Point point = new Point(
(short)((uint)lParam.ToInt32() & 0x0000FFFF),
(short)(((uint)lParam.ToInt32() & 0xFFFF0000) >> 16));
mouse.Position = point;
unsafe
{
Point point = new Point(
(short)((uint)lParam.ToInt32() & 0x0000FFFF),
(short)(((uint)lParam.ToInt32() & 0xFFFF0000) >> 16));
// GetMouseMovePointsEx works with screen coordinates
Point screenPoint = point;
Functions.ClientToScreen(handle, ref screenPoint);
int timestamp = Functions.GetMessageTime();
// & 0xFFFF to handle multiple monitors http://support.microsoft.com/kb/269743
MouseMovePoint movePoint = new MouseMovePoint()
{
X = screenPoint.X & 0xFFFF,
Y = screenPoint.Y & 0xFFFF,
Time = timestamp,
};
// Max points GetMouseMovePointsEx can return is 64.
int numPoints = 64;
MouseMovePoint* movePoints = stackalloc MouseMovePoint[numPoints];
// GetMouseMovePointsEx fills in movePoints so that the most
// recent events are at low indices in the array.
int points = Functions.GetMouseMovePointsEx(
(uint)MouseMovePoint.SizeInBytes,
&movePoint, movePoints, numPoints,
Constants.GMMP_USE_DISPLAY_POINTS);
int lastError = Marshal.GetLastWin32Error();
// No points returned or search point not found
if (points == 0 || (points == -1 && lastError == Constants.ERROR_POINT_NOT_FOUND))
{
// Just use the mouse move position
mouse.Position = point;
}
else if (points == -1)
{
throw new System.ComponentModel.Win32Exception(lastError);
}
else
{
// Exclude the current position.
Point currentScreenPosition = new Point(mouse.X, mouse.Y);
Functions.ClientToScreen(handle, ref currentScreenPosition);
// Find the first move point we've already seen.
int i = 0;
for (i = 0; i < points; ++i)
{
if (movePoints[i].Time < mouse_last_timestamp)
break;
if (movePoints[i].Time == mouse_last_timestamp &&
movePoints[i].X == currentScreenPosition.X &&
movePoints[i].Y == currentScreenPosition.Y)
break;
}
// Now move the mouse to each point before the one just found.
while (--i >= 0)
{
Point position = new Point(movePoints[i].X, movePoints[i].Y);
// Handle multiple monitors http://support.microsoft.com/kb/269743
if (position.X > 32767)
{
position.X -= 65536;
}
if (position.Y > 32767)
{
position.Y -= 65536;
}
Functions.ScreenToClient(handle, ref position);
mouse.Position = position;
}
}
mouse_last_timestamp = timestamp;
}
if (mouse_outside_window)
{