mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-02-25 02:46:55 +00:00
Merge pull request #38 from opentk/issue34
Fix for issue #33 and issue #34
This commit is contained in:
commit
811126c47b
|
@ -151,7 +151,12 @@ namespace OpenTK.Platform.Windows
|
||||||
internal static extern BOOL AdjustWindowRect([In, Out] ref Win32Rectangle lpRect, WindowStyle dwStyle, BOOL bMenu);
|
internal static extern BOOL AdjustWindowRect([In, Out] ref Win32Rectangle lpRect, WindowStyle dwStyle, BOOL bMenu);
|
||||||
|
|
||||||
[DllImport("user32.dll", EntryPoint = "AdjustWindowRectEx", CallingConvention = CallingConvention.StdCall, SetLastError = true), SuppressUnmanagedCodeSecurity]
|
[DllImport("user32.dll", EntryPoint = "AdjustWindowRectEx", CallingConvention = CallingConvention.StdCall, SetLastError = true), SuppressUnmanagedCodeSecurity]
|
||||||
internal static extern bool AdjustWindowRectEx(ref Win32Rectangle lpRect, WindowStyle dwStyle, bool bMenu, ExtendedWindowStyle dwExStyle);
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
internal static extern bool AdjustWindowRectEx(
|
||||||
|
ref Win32Rectangle lpRect,
|
||||||
|
WindowStyle dwStyle,
|
||||||
|
[MarshalAs(UnmanagedType.Bool)] bool bMenu,
|
||||||
|
ExtendedWindowStyle dwExStyle);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -241,9 +246,7 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
#region CallWindowProc
|
#region CallWindowProc
|
||||||
|
|
||||||
#if RELEASE
|
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
#endif
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
internal static extern LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, WindowMessage Msg,
|
internal static extern LRESULT CallWindowProc(WNDPROC lpPrevWndFunc, HWND hWnd, WindowMessage Msg,
|
||||||
WPARAM wParam, LPARAM lParam);
|
WPARAM wParam, LPARAM lParam);
|
||||||
|
@ -264,9 +267,9 @@ namespace OpenTK.Platform.Windows
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
|
|
||||||
if (IntPtr.Size == 4)
|
if (IntPtr.Size == 4)
|
||||||
retval = new IntPtr(SetWindowLong(handle, item, newValue.ToInt32()));
|
retval = new IntPtr(SetWindowLongInternal(handle, item, newValue.ToInt32()));
|
||||||
else
|
else
|
||||||
retval = SetWindowLongPtr(handle, item, newValue);
|
retval = SetWindowLongPtrInternal(handle, item, newValue);
|
||||||
|
|
||||||
if (retval == IntPtr.Zero)
|
if (retval == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
|
@ -283,30 +286,22 @@ namespace OpenTK.Platform.Windows
|
||||||
return SetWindowLong(handle, GetWindowLongOffsets.WNDPROC, Marshal.GetFunctionPointerForDelegate(newValue));
|
return SetWindowLong(handle, GetWindowLongOffsets.WNDPROC, Marshal.GetFunctionPointerForDelegate(newValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if RELASE
|
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
#endif
|
[DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")]
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
static extern LONG SetWindowLongInternal(HWND hWnd, GetWindowLongOffsets nIndex, LONG dwNewLong);
|
||||||
static extern LONG SetWindowLong(HWND hWnd, GetWindowLongOffsets nIndex, LONG dwNewLong);
|
|
||||||
|
|
||||||
#if RELASE
|
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
#endif
|
[DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr")]
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
static extern LONG_PTR SetWindowLongPtrInternal(HWND hWnd, GetWindowLongOffsets nIndex, LONG_PTR dwNewLong);
|
||||||
static extern LONG_PTR SetWindowLongPtr(HWND hWnd, GetWindowLongOffsets nIndex, LONG_PTR dwNewLong);
|
|
||||||
|
|
||||||
#if RELASE
|
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
#endif
|
[DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")]
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
static extern LONG SetWindowLongInternal(HWND hWnd, GetWindowLongOffsets nIndex,
|
||||||
static extern LONG SetWindowLong(HWND hWnd, GetWindowLongOffsets nIndex,
|
|
||||||
[MarshalAs(UnmanagedType.FunctionPtr)]WindowProcedure dwNewLong);
|
[MarshalAs(UnmanagedType.FunctionPtr)]WindowProcedure dwNewLong);
|
||||||
|
|
||||||
#if RELASE
|
|
||||||
[SuppressUnmanagedCodeSecurity]
|
[SuppressUnmanagedCodeSecurity]
|
||||||
#endif
|
[DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr")]
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
static extern LONG_PTR SetWindowLongPtrInternal(HWND hWnd, GetWindowLongOffsets nIndex,
|
||||||
static extern LONG_PTR SetWindowLongPtr(HWND hWnd, GetWindowLongOffsets nIndex,
|
|
||||||
[MarshalAs(UnmanagedType.FunctionPtr)]WindowProcedure dwNewLong);
|
[MarshalAs(UnmanagedType.FunctionPtr)]WindowProcedure dwNewLong);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -407,9 +402,7 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
#region DispatchMessage
|
#region DispatchMessage
|
||||||
|
|
||||||
#if RELEASE
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[System.Security.SuppressUnmanagedCodeSecurity]
|
|
||||||
#endif
|
|
||||||
[DllImport("User32.dll"), CLSCompliant(false)]
|
[DllImport("User32.dll"), CLSCompliant(false)]
|
||||||
internal static extern LRESULT DispatchMessage(ref MSG msg);
|
internal static extern LRESULT DispatchMessage(ref MSG msg);
|
||||||
|
|
||||||
|
@ -417,9 +410,7 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
#region TranslateMessage
|
#region TranslateMessage
|
||||||
|
|
||||||
#if RELEASE
|
[SuppressUnmanagedCodeSecurity]
|
||||||
[System.Security.SuppressUnmanagedCodeSecurity]
|
|
||||||
#endif
|
|
||||||
[DllImport("User32.dll"), CLSCompliant(false)]
|
[DllImport("User32.dll"), CLSCompliant(false)]
|
||||||
internal static extern BOOL TranslateMessage(ref MSG lpMsg);
|
internal static extern BOOL TranslateMessage(ref MSG lpMsg);
|
||||||
|
|
||||||
|
@ -3752,7 +3743,7 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
#region WindowMessage
|
#region WindowMessage
|
||||||
|
|
||||||
internal enum WindowMessage : uint
|
internal enum WindowMessage : int
|
||||||
{
|
{
|
||||||
NULL = 0x0000,
|
NULL = 0x0000,
|
||||||
CREATE = 0x0001,
|
CREATE = 0x0001,
|
||||||
|
|
|
@ -240,6 +240,333 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Message Handlers
|
||||||
|
|
||||||
|
void HandleActivate(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/ms646274(VS.85).aspx (WM_ACTIVATE notification):
|
||||||
|
// wParam: The low-order word specifies whether the window is being activated or deactivated.
|
||||||
|
bool new_focused_state = Focused;
|
||||||
|
if (IntPtr.Size == 4)
|
||||||
|
focused = (wParam.ToInt32() & 0xFFFF) != 0;
|
||||||
|
else
|
||||||
|
focused = (wParam.ToInt64() & 0xFFFF) != 0;
|
||||||
|
|
||||||
|
if (new_focused_state != Focused)
|
||||||
|
FocusedChanged(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleEnterModalLoop(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
// Entering the modal size/move loop: we don't want rendering to
|
||||||
|
// stop during this time, so we register a timer callback to continue
|
||||||
|
// processing from time to time.
|
||||||
|
is_in_modal_loop = true;
|
||||||
|
StartTimer(handle);
|
||||||
|
|
||||||
|
if (!CursorVisible)
|
||||||
|
UngrabCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleExitModalLoop(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
// Exiting from Modal size/move loop: the timer callback is no longer
|
||||||
|
// necessary.
|
||||||
|
is_in_modal_loop = false;
|
||||||
|
StopTimer(handle);
|
||||||
|
|
||||||
|
// Ensure cursor remains grabbed
|
||||||
|
if (!CursorVisible)
|
||||||
|
GrabCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleWindowPositionChanged(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
WindowPosition* pos = (WindowPosition*)lParam;
|
||||||
|
if (window != null && pos->hwnd == window.Handle)
|
||||||
|
{
|
||||||
|
Point new_location = new Point(pos->x, pos->y);
|
||||||
|
if (Location != new_location)
|
||||||
|
{
|
||||||
|
bounds.Location = new_location;
|
||||||
|
Move(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
Size new_size = new Size(pos->cx, pos->cy);
|
||||||
|
if (Size != new_size)
|
||||||
|
{
|
||||||
|
bounds.Width = pos->cx;
|
||||||
|
bounds.Height = pos->cy;
|
||||||
|
|
||||||
|
Win32Rectangle rect;
|
||||||
|
Functions.GetClientRect(handle, out rect);
|
||||||
|
client_rectangle = rect.ToRectangle();
|
||||||
|
|
||||||
|
Functions.SetWindowPos(child_window.Handle, IntPtr.Zero, 0, 0, ClientRectangle.Width, ClientRectangle.Height,
|
||||||
|
SetWindowPosFlags.NOZORDER | SetWindowPosFlags.NOOWNERZORDER |
|
||||||
|
SetWindowPosFlags.NOACTIVATE | SetWindowPosFlags.NOSENDCHANGING);
|
||||||
|
|
||||||
|
if (suppress_resize <= 0)
|
||||||
|
Resize(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_in_modal_loop)
|
||||||
|
{
|
||||||
|
// If we are in a modal resize/move loop, cursor grabbing is
|
||||||
|
// handled inside [ENTER|EXIT]SIZEMOVE case above.
|
||||||
|
// If not, then we have to handle cursor grabbing here.
|
||||||
|
if (!CursorVisible)
|
||||||
|
GrabCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleStyleChanged(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
WindowBorder old_border = windowBorder;
|
||||||
|
WindowBorder new_border = old_border;
|
||||||
|
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
GWL get_window_style = (GWL)unchecked(wParam.ToInt32());
|
||||||
|
if ((get_window_style & (GWL.STYLE | GWL.EXSTYLE)) != 0)
|
||||||
|
{
|
||||||
|
WindowStyle style = ((StyleStruct*)lParam)->New;
|
||||||
|
if ((style & WindowStyle.Popup) != 0)
|
||||||
|
new_border = WindowBorder.Hidden;
|
||||||
|
else if ((style & WindowStyle.ThickFrame) != 0)
|
||||||
|
new_border = WindowBorder.Resizable;
|
||||||
|
else if ((style & ~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox)) != 0)
|
||||||
|
new_border = WindowBorder.Fixed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_border != windowBorder)
|
||||||
|
{
|
||||||
|
// Ensure cursor remains grabbed
|
||||||
|
if (!CursorVisible)
|
||||||
|
GrabCursor();
|
||||||
|
|
||||||
|
windowBorder = new_border;
|
||||||
|
WindowBorderChanged(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleSize(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
SizeMessage state = (SizeMessage)wParam.ToInt64();
|
||||||
|
WindowState new_state = windowState;
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case SizeMessage.RESTORED:
|
||||||
|
new_state = borderless_maximized_window_state ?
|
||||||
|
WindowState.Maximized : WindowState.Normal;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SizeMessage.MINIMIZED:
|
||||||
|
new_state = WindowState.Minimized;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SizeMessage.MAXIMIZED:
|
||||||
|
new_state = WindowBorder == WindowBorder.Hidden ?
|
||||||
|
WindowState.Fullscreen : WindowState.Maximized;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_state != windowState)
|
||||||
|
{
|
||||||
|
windowState = new_state;
|
||||||
|
WindowStateChanged(this, EventArgs.Empty);
|
||||||
|
|
||||||
|
// Ensure cursor remains grabbed
|
||||||
|
if (!CursorVisible)
|
||||||
|
GrabCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleChar(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
if (IntPtr.Size == 4)
|
||||||
|
key_press.KeyChar = (char)wParam.ToInt32();
|
||||||
|
else
|
||||||
|
key_press.KeyChar = (char)wParam.ToInt64();
|
||||||
|
|
||||||
|
KeyPress(this, key_press);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
MouseEnter(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleMouseLeave(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
mouse_outside_window = true;
|
||||||
|
// Mouse tracking is disabled automatically by the OS
|
||||||
|
|
||||||
|
MouseLeave(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleMouseWheel(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
|
||||||
|
mouse.WheelPrecise += ((long)wParam << 32 >> 48) / 120.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleLButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
Functions.SetCapture(window.Handle);
|
||||||
|
mouse[MouseButton.Left] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleMButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
Functions.SetCapture(window.Handle);
|
||||||
|
mouse[MouseButton.Middle] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleRButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
Functions.SetCapture(window.Handle);
|
||||||
|
mouse[MouseButton.Right] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleXButtonDown(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
Functions.SetCapture(window.Handle);
|
||||||
|
mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) !=
|
||||||
|
(int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleLButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
Functions.ReleaseCapture();
|
||||||
|
mouse[MouseButton.Left] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleMButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
Functions.ReleaseCapture();
|
||||||
|
mouse[MouseButton.Middle] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleRButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
Functions.ReleaseCapture();
|
||||||
|
mouse[MouseButton.Right] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleXButtonUp(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
Functions.ReleaseCapture();
|
||||||
|
mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) !=
|
||||||
|
(int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleKeyboard(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
bool pressed =
|
||||||
|
message == WindowMessage.KEYDOWN ||
|
||||||
|
message == WindowMessage.SYSKEYDOWN;
|
||||||
|
|
||||||
|
// Shift/Control/Alt behave strangely when e.g. ShiftRight is held down and ShiftLeft is pressed
|
||||||
|
// and released. It looks like neither key is released in this case, or that the wrong key is
|
||||||
|
// released in the case of Control and Alt.
|
||||||
|
// To combat this, we are going to release both keys when either is released. Hacky, but should work.
|
||||||
|
// Win95 does not distinguish left/right key constants (GetAsyncKeyState returns 0).
|
||||||
|
// In this case, both keys will be reported as pressed.
|
||||||
|
|
||||||
|
bool extended = (lParam.ToInt64() & ExtendedBit) != 0;
|
||||||
|
short scancode = (short)((lParam.ToInt64() >> 16) & 0xFF);
|
||||||
|
VirtualKeys vkey = (VirtualKeys)wParam;
|
||||||
|
bool is_valid;
|
||||||
|
Key key = KeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid);
|
||||||
|
|
||||||
|
if (is_valid)
|
||||||
|
{
|
||||||
|
keyboard.SetKey(key, (byte)scancode, pressed);
|
||||||
|
|
||||||
|
if (pressed)
|
||||||
|
{
|
||||||
|
key_down.Key = key;
|
||||||
|
KeyDown(this, key_down);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
key_up.Key = key;
|
||||||
|
KeyUp(this, key_up);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleKillFocus(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
keyboard.ClearKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleCreate(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
CreateStruct cs = (CreateStruct)Marshal.PtrToStructure(lParam, typeof(CreateStruct));
|
||||||
|
if (cs.hwndParent == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
bounds.X = cs.x;
|
||||||
|
bounds.Y = cs.y;
|
||||||
|
bounds.Width = cs.cx;
|
||||||
|
bounds.Height = cs.cy;
|
||||||
|
|
||||||
|
Win32Rectangle rect;
|
||||||
|
Functions.GetClientRect(handle, out rect);
|
||||||
|
client_rectangle = rect.ToRectangle();
|
||||||
|
|
||||||
|
invisible_since_creation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleClose(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
System.ComponentModel.CancelEventArgs e = new System.ComponentModel.CancelEventArgs();
|
||||||
|
|
||||||
|
Closing(this, e);
|
||||||
|
|
||||||
|
if (!e.Cancel)
|
||||||
|
{
|
||||||
|
DestroyWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleDestroy(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
exists = false;
|
||||||
|
|
||||||
|
if (handle == window.Handle)
|
||||||
|
{
|
||||||
|
Functions.UnregisterClass(ClassName, Instance);
|
||||||
|
}
|
||||||
|
window.Dispose();
|
||||||
|
child_window.Dispose();
|
||||||
|
|
||||||
|
Closed(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region WindowProcedure
|
#region WindowProcedure
|
||||||
|
|
||||||
IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam)
|
||||||
|
@ -249,132 +576,32 @@ namespace OpenTK.Platform.Windows
|
||||||
#region Size / Move / Style events
|
#region Size / Move / Style events
|
||||||
|
|
||||||
case WindowMessage.ACTIVATE:
|
case WindowMessage.ACTIVATE:
|
||||||
// See http://msdn.microsoft.com/en-us/library/ms646274(VS.85).aspx (WM_ACTIVATE notification):
|
HandleActivate(handle, message, wParam, lParam);
|
||||||
// wParam: The low-order word specifies whether the window is being activated or deactivated.
|
|
||||||
bool new_focused_state = Focused;
|
|
||||||
if (IntPtr.Size == 4)
|
|
||||||
focused = (wParam.ToInt32() & 0xFFFF) != 0;
|
|
||||||
else
|
|
||||||
focused = (wParam.ToInt64() & 0xFFFF) != 0;
|
|
||||||
|
|
||||||
if (new_focused_state != Focused)
|
|
||||||
FocusedChanged(this, EventArgs.Empty);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.ENTERMENULOOP:
|
case WindowMessage.ENTERMENULOOP:
|
||||||
case WindowMessage.ENTERSIZEMOVE:
|
case WindowMessage.ENTERSIZEMOVE:
|
||||||
// Entering the modal size/move loop: we don't want rendering to
|
HandleEnterModalLoop(handle, message, wParam, lParam);
|
||||||
// stop during this time, so we register a timer callback to continue
|
|
||||||
// processing from time to time.
|
|
||||||
is_in_modal_loop = true;
|
|
||||||
StartTimer(handle);
|
|
||||||
|
|
||||||
if (!CursorVisible)
|
|
||||||
UngrabCursor();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.EXITMENULOOP:
|
case WindowMessage.EXITMENULOOP:
|
||||||
case WindowMessage.EXITSIZEMOVE:
|
case WindowMessage.EXITSIZEMOVE:
|
||||||
// Exiting from Modal size/move loop: the timer callback is no longer
|
HandleExitModalLoop(handle, message, wParam, lParam);
|
||||||
// necessary.
|
|
||||||
is_in_modal_loop = false;
|
|
||||||
StopTimer(handle);
|
|
||||||
|
|
||||||
// Ensure cursor remains grabbed
|
|
||||||
if (!CursorVisible)
|
|
||||||
GrabCursor();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.ERASEBKGND:
|
case WindowMessage.ERASEBKGND:
|
||||||
return new IntPtr(1);
|
return new IntPtr(1);
|
||||||
|
|
||||||
case WindowMessage.WINDOWPOSCHANGED:
|
case WindowMessage.WINDOWPOSCHANGED:
|
||||||
unsafe
|
HandleWindowPositionChanged(handle, message, wParam, lParam);
|
||||||
{
|
|
||||||
WindowPosition* pos = (WindowPosition*)lParam;
|
|
||||||
if (window != null && pos->hwnd == window.Handle)
|
|
||||||
{
|
|
||||||
Point new_location = new Point(pos->x, pos->y);
|
|
||||||
if (Location != new_location)
|
|
||||||
{
|
|
||||||
bounds.Location = new_location;
|
|
||||||
Move(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
Size new_size = new Size(pos->cx, pos->cy);
|
|
||||||
if (Size != new_size)
|
|
||||||
{
|
|
||||||
bounds.Width = pos->cx;
|
|
||||||
bounds.Height = pos->cy;
|
|
||||||
|
|
||||||
Win32Rectangle rect;
|
|
||||||
Functions.GetClientRect(handle, out rect);
|
|
||||||
client_rectangle = rect.ToRectangle();
|
|
||||||
|
|
||||||
Functions.SetWindowPos(child_window.Handle, IntPtr.Zero, 0, 0, ClientRectangle.Width, ClientRectangle.Height,
|
|
||||||
SetWindowPosFlags.NOZORDER | SetWindowPosFlags.NOOWNERZORDER |
|
|
||||||
SetWindowPosFlags.NOACTIVATE | SetWindowPosFlags.NOSENDCHANGING);
|
|
||||||
|
|
||||||
if (suppress_resize <= 0)
|
|
||||||
Resize(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_in_modal_loop)
|
|
||||||
{
|
|
||||||
// If we are in a modal resize/move loop, cursor grabbing is
|
|
||||||
// handled inside [ENTER|EXIT]SIZEMOVE case above.
|
|
||||||
// If not, then we have to handle cursor grabbing here.
|
|
||||||
if (!CursorVisible)
|
|
||||||
GrabCursor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.STYLECHANGED:
|
case WindowMessage.STYLECHANGED:
|
||||||
unsafe
|
HandleStyleChanged(handle, message, wParam, lParam);
|
||||||
{
|
|
||||||
if (wParam.ToInt64() == (long)GWL.STYLE)
|
|
||||||
{
|
|
||||||
WindowStyle style = ((StyleStruct*)lParam)->New;
|
|
||||||
if ((style & WindowStyle.Popup) != 0)
|
|
||||||
windowBorder = WindowBorder.Hidden;
|
|
||||||
else if ((style & WindowStyle.ThickFrame) != 0)
|
|
||||||
windowBorder = WindowBorder.Resizable;
|
|
||||||
else if ((style & ~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox)) != 0)
|
|
||||||
windowBorder = WindowBorder.Fixed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure cursor remains grabbed
|
|
||||||
if (!CursorVisible)
|
|
||||||
GrabCursor();
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.SIZE:
|
case WindowMessage.SIZE:
|
||||||
SizeMessage state = (SizeMessage)wParam.ToInt64();
|
HandleSize(handle, message, wParam, lParam);
|
||||||
WindowState new_state = windowState;
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case SizeMessage.RESTORED: new_state = borderless_maximized_window_state ?
|
|
||||||
WindowState.Maximized : WindowState.Normal; break;
|
|
||||||
case SizeMessage.MINIMIZED: new_state = WindowState.Minimized; break;
|
|
||||||
case SizeMessage.MAXIMIZED: new_state = WindowBorder == WindowBorder.Hidden ?
|
|
||||||
WindowState.Fullscreen : WindowState.Maximized;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_state != windowState)
|
|
||||||
{
|
|
||||||
windowState = new_state;
|
|
||||||
WindowStateChanged(this, EventArgs.Empty);
|
|
||||||
|
|
||||||
// Ensure cursor remains grabbed
|
|
||||||
if (!CursorVisible)
|
|
||||||
GrabCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -382,84 +609,51 @@ namespace OpenTK.Platform.Windows
|
||||||
#region Input events
|
#region Input events
|
||||||
|
|
||||||
case WindowMessage.CHAR:
|
case WindowMessage.CHAR:
|
||||||
if (IntPtr.Size == 4)
|
HandleChar(handle, message, wParam, lParam);
|
||||||
key_press.KeyChar = (char)wParam.ToInt32();
|
|
||||||
else
|
|
||||||
key_press.KeyChar = (char)wParam.ToInt64();
|
|
||||||
|
|
||||||
KeyPress(this, key_press);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.MOUSEMOVE:
|
case WindowMessage.MOUSEMOVE:
|
||||||
Point point = new Point(
|
HandleMouseMove(handle, message, wParam, lParam);
|
||||||
(short)((uint)lParam.ToInt32() & 0x0000FFFF),
|
|
||||||
(short)(((uint)lParam.ToInt32() & 0xFFFF0000) >> 16));
|
|
||||||
mouse.Position = point;
|
|
||||||
|
|
||||||
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();
|
|
||||||
|
|
||||||
MouseEnter(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.MOUSELEAVE:
|
case WindowMessage.MOUSELEAVE:
|
||||||
mouse_outside_window = true;
|
HandleMouseLeave(handle, message, wParam, lParam);
|
||||||
// Mouse tracking is disabled automatically by the OS
|
|
||||||
|
|
||||||
MouseLeave(this, EventArgs.Empty);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.MOUSEWHEEL:
|
case WindowMessage.MOUSEWHEEL:
|
||||||
// This is due to inconsistent behavior of the WParam value on 64bit arch, whese
|
HandleMouseWheel(handle, message, wParam, lParam);
|
||||||
// wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000
|
|
||||||
mouse.WheelPrecise += ((long)wParam << 32 >> 48) / 120.0f;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.LBUTTONDOWN:
|
case WindowMessage.LBUTTONDOWN:
|
||||||
Functions.SetCapture(window.Handle);
|
HandleLButtonDown(handle, message, wParam, lParam);
|
||||||
mouse[MouseButton.Left] = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.MBUTTONDOWN:
|
case WindowMessage.MBUTTONDOWN:
|
||||||
Functions.SetCapture(window.Handle);
|
HandleMButtonDown(handle, message, wParam, lParam);
|
||||||
mouse[MouseButton.Middle] = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.RBUTTONDOWN:
|
case WindowMessage.RBUTTONDOWN:
|
||||||
Functions.SetCapture(window.Handle);
|
HandleRButtonDown(handle, message, wParam, lParam);
|
||||||
mouse[MouseButton.Right] = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.XBUTTONDOWN:
|
case WindowMessage.XBUTTONDOWN:
|
||||||
Functions.SetCapture(window.Handle);
|
HandleXButtonDown(handle, message, wParam, lParam);
|
||||||
mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) !=
|
|
||||||
(int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = true;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.LBUTTONUP:
|
case WindowMessage.LBUTTONUP:
|
||||||
Functions.ReleaseCapture();
|
HandleLButtonUp(handle, message, wParam, lParam);
|
||||||
mouse[MouseButton.Left] = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.MBUTTONUP:
|
case WindowMessage.MBUTTONUP:
|
||||||
Functions.ReleaseCapture();
|
HandleMButtonUp(handle, message, wParam, lParam);
|
||||||
mouse[MouseButton.Middle] = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.RBUTTONUP:
|
case WindowMessage.RBUTTONUP:
|
||||||
Functions.ReleaseCapture();
|
HandleRButtonUp(handle, message, wParam, lParam);
|
||||||
mouse[MouseButton.Right] = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.XBUTTONUP:
|
case WindowMessage.XBUTTONUP:
|
||||||
Functions.ReleaseCapture();
|
HandleXButtonUp(handle, message, wParam, lParam);
|
||||||
mouse[((wParam.ToInt32() & 0xFFFF0000) >> 16) !=
|
|
||||||
(int)MouseKeys.XButton1 ? MouseButton.Button1 : MouseButton.Button2] = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Keyboard events:
|
// Keyboard events:
|
||||||
|
@ -467,47 +661,14 @@ namespace OpenTK.Platform.Windows
|
||||||
case WindowMessage.KEYUP:
|
case WindowMessage.KEYUP:
|
||||||
case WindowMessage.SYSKEYDOWN:
|
case WindowMessage.SYSKEYDOWN:
|
||||||
case WindowMessage.SYSKEYUP:
|
case WindowMessage.SYSKEYUP:
|
||||||
bool pressed =
|
HandleKeyboard(handle, message, wParam, lParam);
|
||||||
message == WindowMessage.KEYDOWN ||
|
|
||||||
message == WindowMessage.SYSKEYDOWN;
|
|
||||||
|
|
||||||
// Shift/Control/Alt behave strangely when e.g. ShiftRight is held down and ShiftLeft is pressed
|
|
||||||
// and released. It looks like neither key is released in this case, or that the wrong key is
|
|
||||||
// released in the case of Control and Alt.
|
|
||||||
// To combat this, we are going to release both keys when either is released. Hacky, but should work.
|
|
||||||
// Win95 does not distinguish left/right key constants (GetAsyncKeyState returns 0).
|
|
||||||
// In this case, both keys will be reported as pressed.
|
|
||||||
|
|
||||||
bool extended = (lParam.ToInt64() & ExtendedBit) != 0;
|
|
||||||
short scancode = (short)((lParam.ToInt64() >> 16) & 0xFF);
|
|
||||||
VirtualKeys vkey = (VirtualKeys)wParam;
|
|
||||||
bool is_valid;
|
|
||||||
Key key = KeyMap.TranslateKey(scancode, vkey, extended, false, out is_valid);
|
|
||||||
|
|
||||||
if (is_valid)
|
|
||||||
{
|
|
||||||
keyboard.SetKey(key, (byte)scancode, pressed);
|
|
||||||
|
|
||||||
if (pressed)
|
|
||||||
{
|
|
||||||
key_down.Key = key;
|
|
||||||
KeyDown(this, key_down);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
key_up.Key = key;
|
|
||||||
KeyUp(this, key_up);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
|
|
||||||
case WindowMessage.SYSCHAR:
|
case WindowMessage.SYSCHAR:
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
|
|
||||||
case WindowMessage.KILLFOCUS:
|
case WindowMessage.KILLFOCUS:
|
||||||
keyboard.ClearKeys();
|
HandleKillFocus(handle, message, wParam, lParam);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -515,44 +676,15 @@ namespace OpenTK.Platform.Windows
|
||||||
#region Creation / Destruction events
|
#region Creation / Destruction events
|
||||||
|
|
||||||
case WindowMessage.CREATE:
|
case WindowMessage.CREATE:
|
||||||
CreateStruct cs = (CreateStruct)Marshal.PtrToStructure(lParam, typeof(CreateStruct));
|
HandleCreate(handle, message, wParam, lParam);
|
||||||
if (cs.hwndParent == IntPtr.Zero)
|
|
||||||
{
|
|
||||||
bounds.X = cs.x;
|
|
||||||
bounds.Y = cs.y;
|
|
||||||
bounds.Width = cs.cx;
|
|
||||||
bounds.Height = cs.cy;
|
|
||||||
|
|
||||||
Win32Rectangle rect;
|
|
||||||
Functions.GetClientRect(handle, out rect);
|
|
||||||
client_rectangle = rect.ToRectangle();
|
|
||||||
|
|
||||||
invisible_since_creation = true;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowMessage.CLOSE:
|
case WindowMessage.CLOSE:
|
||||||
System.ComponentModel.CancelEventArgs e = new System.ComponentModel.CancelEventArgs();
|
HandleClose(handle, message, wParam, lParam);
|
||||||
|
|
||||||
Closing(this, e);
|
|
||||||
|
|
||||||
if (!e.Cancel)
|
|
||||||
{
|
|
||||||
DestroyWindow();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
|
|
||||||
case WindowMessage.DESTROY:
|
case WindowMessage.DESTROY:
|
||||||
exists = false;
|
HandleDestroy(handle, message, wParam, lParam);
|
||||||
|
|
||||||
Functions.UnregisterClass(ClassName, Instance);
|
|
||||||
window.Dispose();
|
|
||||||
child_window.Dispose();
|
|
||||||
|
|
||||||
Closed(this, EventArgs.Empty);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -1117,34 +1249,35 @@ namespace OpenTK.Platform.Windows
|
||||||
WindowState state = WindowState;
|
WindowState state = WindowState;
|
||||||
ResetWindowState();
|
ResetWindowState();
|
||||||
|
|
||||||
WindowStyle style = WindowStyle.ClipChildren | WindowStyle.ClipSiblings;
|
WindowStyle old_style = WindowStyle.ClipChildren | WindowStyle.ClipSiblings;
|
||||||
|
WindowStyle new_style = old_style;
|
||||||
|
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case WindowBorder.Resizable:
|
case WindowBorder.Resizable:
|
||||||
style |= WindowStyle.OverlappedWindow;
|
new_style |= WindowStyle.OverlappedWindow;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowBorder.Fixed:
|
case WindowBorder.Fixed:
|
||||||
style |= WindowStyle.OverlappedWindow &
|
new_style |= WindowStyle.OverlappedWindow &
|
||||||
~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox | WindowStyle.SizeBox);
|
~(WindowStyle.ThickFrame | WindowStyle.MaximizeBox | WindowStyle.SizeBox);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WindowBorder.Hidden:
|
case WindowBorder.Hidden:
|
||||||
style |= WindowStyle.Popup;
|
new_style |= WindowStyle.Popup;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure client size doesn't change when changing the border style.
|
// Make sure client size doesn't change when changing the border style.
|
||||||
Size client_size = ClientSize;
|
Size client_size = ClientSize;
|
||||||
Win32Rectangle rect = Win32Rectangle.From(client_size);
|
Win32Rectangle rect = Win32Rectangle.From(client_size);
|
||||||
Functions.AdjustWindowRectEx(ref rect, style, false, ParentStyleEx);
|
Functions.AdjustWindowRectEx(ref rect, new_style, false, ParentStyleEx);
|
||||||
|
|
||||||
// This avoids leaving garbage on the background window.
|
// This avoids leaving garbage on the background window.
|
||||||
if (was_visible)
|
if (was_visible)
|
||||||
Visible = false;
|
Visible = false;
|
||||||
|
|
||||||
Functions.SetWindowLong(window.Handle, GetWindowLongOffsets.STYLE, (IntPtr)(int)style);
|
Functions.SetWindowLong(window.Handle, GetWindowLongOffsets.STYLE, (IntPtr)(int)new_style);
|
||||||
Functions.SetWindowPos(window.Handle, IntPtr.Zero, 0, 0, rect.Width, rect.Height,
|
Functions.SetWindowPos(window.Handle, IntPtr.Zero, 0, 0, rect.Width, rect.Height,
|
||||||
SetWindowPosFlags.NOMOVE | SetWindowPosFlags.NOZORDER |
|
SetWindowPosFlags.NOMOVE | SetWindowPosFlags.NOZORDER |
|
||||||
SetWindowPosFlags.FRAMECHANGED);
|
SetWindowPosFlags.FRAMECHANGED);
|
||||||
|
@ -1157,7 +1290,23 @@ namespace OpenTK.Platform.Windows
|
||||||
|
|
||||||
WindowState = state;
|
WindowState = state;
|
||||||
|
|
||||||
WindowBorderChanged(this, EventArgs.Empty);
|
// Workaround for github issues #33 and #34,
|
||||||
|
// where WindowMessage.STYLECHANGED is not
|
||||||
|
// delivered when running on Mono/Windows.
|
||||||
|
if (Configuration.RunningOnMono)
|
||||||
|
{
|
||||||
|
StyleStruct style = new StyleStruct();
|
||||||
|
style.New = new_style;
|
||||||
|
style.Old = old_style;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
HandleStyleChanged(
|
||||||
|
window.Handle,
|
||||||
|
WindowMessage.STYLECHANGED,
|
||||||
|
new IntPtr((int)(GWL.STYLE | GWL.EXSTYLE)),
|
||||||
|
new IntPtr(&style));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue