/// <inheritdoc />
        protected override void SetupPlatform(Configurator config)
        {
            // todo: load libraries - if any
            // probably XInput

            // Initialize audio - Try to create WasApi - otherwise return the fake context so execution can go on.
            Audio = WasApiAudioContext.TryCreate() ?? (AudioContext) new NullAudioContext();
            Engine.Log.Trace("Audio init complete.", MessageSource.Win32);

            PopulateKeyNames();

            if (IsWindows10CreatorsUpdateOrGreaterWin32)
            {
                User32.SetProcessDpiAwarenessContext(DpiAwarenessContext.DpiAwarenessContextPerMonitorAwareV2);
            }
            else if (IsWindows81OrGreater)
            {
                User32.SetProcessDpiAwareness(ProcessDpiAwareness.ProcessPerMonitorDpiAware);
            }
            else
            {
                User32.SetProcessDPIAware();
            }

            RegisterWindowClass();
            CreateHelperWindow();
            PollMonitors();
            Engine.Log.Trace("Platform init complete.", MessageSource.Win32);

            var windowInitialSize = new Rect
            {
                Right  = (int)config.HostSize.X,
                Bottom = (int)config.HostSize.Y
            };

            Win32Window.GetFullWindowRect(Win32Window.DEFAULT_WINDOW_STYLE, Win32Window.DEFAULT_WINDOW_STYLE_EX, DEFAULT_DPI, ref windowInitialSize);
            int    initialWidth  = windowInitialSize.Right - windowInitialSize.Left;
            int    initialHeight = windowInitialSize.Bottom - windowInitialSize.Top;
            IntPtr handle        = User32.CreateWindowEx(
                Win32Window.DEFAULT_WINDOW_STYLE_EX,
                CLASS_NAME,
                config.HostTitle,
                Win32Window.DEFAULT_WINDOW_STYLE,
                (int)CreateWindowFlags.CW_USEDEFAULT, (int)CreateWindowFlags.CW_USEDEFAULT, // Position - default
                initialWidth, initialHeight,                                                // Size - initial
                IntPtr.Zero,                                                                // No parent window
                IntPtr.Zero,                                                                // No window menu
                Kernel32.GetModuleHandle(null),
                IntPtr.Zero
                );

            if (handle == IntPtr.Zero)
            {
                CheckError("Couldn't create window.", true);
                return;
            }

            Engine.Log.Trace("Window created.", MessageSource.Win32);

            // Create graphics context - OpenGL.
            GraphicsContext context = null;

            try
            {
                var wgl = new WglGraphicsContext();
                wgl.Init(handle, this);
                if (wgl.Valid)
                {
                    context = wgl;
                }
            }
            catch (Exception ex)
            {
                Engine.Log.Warning($"Couldn't create WGL context, falling back to MESA if possible.\n{ex}", MessageSource.Win32);
            }

            if (context == null)
            {
                try
                {
                    var gallium = new GalliumGraphicsContext();
                    gallium.Init(handle, this);
                    if (gallium.Valid)
                    {
                        context = gallium;
                    }
                }
                catch (Exception ex)
                {
                    Engine.SubmitError(new Exception("Couldn't create MESA context.", ex));
                }
            }

            if (context == null)
            {
                Engine.SubmitError(new Exception("Couldn't create graphics context!"));
                return;
            }

            // Create Emotion representation of the window.
            var windowInstance = new Win32Window(handle, context, this);

            // Adjust window size to account for DPI scaling of the window frame and optionally DPI scaling of the content area.
            // This cannot be done until we know what monitor it was placed on - so it's done post creation.
            var rect = new Rect
            {
                Right  = (int)config.HostSize.X,
                Bottom = (int)config.HostSize.Y
            };

            rect.ClientToScreen(windowInstance.Handle);
            windowInstance.GetFullWindowRect(ref rect);
            User32.SetWindowPos(windowInstance.Handle, IntPtr.Zero,
                                rect.Left, rect.Top,
                                rect.Right - rect.Left, rect.Bottom - rect.Top,
                                WindowPositionFlags.SWP_NOACTIVATE | WindowPositionFlags.SWP_NOZORDER);
            Window = windowInstance;
        }
        /// <summary>
        /// Handler for messages.
        /// </summary>
        private unsafe IntPtr WndProc(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam)
        {
            // Check if the message is for the main window.
            Win32Window win = null;

            if (Window != null && hWnd == ((Win32Window)Window).Handle)
            {
                win = (Win32Window)Window;
            }

            if (win == null)
            {
                // This is the message handling for the hidden helper window
                // and for a regular window during its initial creation

                switch (msg)
                {
                case WM.CREATE:
                    if (IsWindows10AnniversaryUpdateOrGreaterWin32)
                    {
                        User32.EnableNonClientDpiScaling(hWnd);
                    }
                    break;

                case WM.DISPLAYCHANGE:
                    PollMonitors();
                    break;

                case WM.DEVICECHANGE:
                    break;
                }

                return(User32.DefWindowProc(hWnd, msg, wParam, lParam));
            }

            switch (msg)
            {
            case WM.GETMINMAXINFO:
                Rect windowR = win.GetFullWindowRect(0, 0);
                // ReSharper disable once NotAccessedVariable
                var mmi = (MinMaxInfo *)lParam;

                int offX = windowR.Right - windowR.Left;
                int offY = windowR.Bottom - windowR.Top;
                mmi->MinTrackSize.X = (int)Engine.Configuration.RenderSize.X + offX;
                mmi->MinTrackSize.Y = (int)Engine.Configuration.RenderSize.Y + offY;

                return(IntPtr.Zero);

            case WM.SIZE:

                int width  = NativeHelpers.LoWord((uint)lParam);
                int height = NativeHelpers.HiWord((uint)lParam);

                // Don't send resize event when minimized.
                if (width != 0 && height != 0)
                {
                    win.OnResize.Invoke(new Vector2(width, height));
                }

                return(IntPtr.Zero);

            case WM.SETFOCUS:
                UpdateFocus(true);
                return(IntPtr.Zero);

            case WM.KILLFOCUS:
                UpdateFocus(false);
                return(IntPtr.Zero);

            case WM.SYSCOMMAND:

                switch ((int)wParam & 0xfff0)
                {
                case (int)SysCommand.SC_SCREENSAVE:
                case (int)SysCommand.SC_MONITORPOWER:
                    if (Window.DisplayMode == DisplayMode.Fullscreen)
                    {
                        // We are running in full screen mode, so disallow
                        // screen saver and screen blanking
                        return(IntPtr.Zero);
                    }

                    break;

                // User trying to access application menu using ALT?
                case (int)SysCommand.SC_KEYMENU:
                    return(IntPtr.Zero);
                }

                break;

            case WM.CLOSE:
                IsOpen = false;
                return(IntPtr.Zero);

            // ------------------- INPUT -------------------
            case WM.INPUTLANGCHANGE:
                PopulateKeyNames();
                break;

            case WM.CHAR:
            case WM.SYSCHAR:
            case WM.UNICHAR:

                if (msg == WM.UNICHAR && (int)wParam == 0xFFFF)
                {
                    // WM_UNICHAR is not sent by Windows, but is sent by some
                    // third-party input method engine
                    // Returning TRUE here announces support for this message
                    return((IntPtr)1);
                }

                OnTextInput.Invoke((char)wParam);

                break;

            case WM.KEYDOWN:
            case WM.SYSKEYDOWN:
            case WM.KEYUP:
            case WM.SYSKEYUP:

                var lParamLong = (ulong)lParam;
                Key key        = TranslateKey((ulong)wParam, lParamLong);
                if (key == Key.Unknown)
                {
                    break;
                }

                // Scan code can be used for debugging purposes.
                //uint scanCode = NativeHelpers.HiWord(lParamLong) & (uint) 0x1ff;
                bool up = (((ulong)lParam >> 31) & 1) != 0;

                if (up && (uint)wParam == (uint)VirtualKey.SHIFT)
                {
                    // HACK: Release both Shift keys on Shift up event, as when both
                    //       are pressed the first release does not emit any event
                    // NOTE: The other half of this is in Update()
                    UpdateKeyStatus(Key.LeftShift, false);
                    UpdateKeyStatus(Key.RightShift, false);
                }
                else
                {
                    UpdateKeyStatus(key, !up);
                }

                break;

            case WM.MOUSEMOVE:

                int x = NativeHelpers.LoWord((uint)lParam);
                int y = NativeHelpers.HiWord((uint)lParam);

                var pos = new Vector2(x, y);
                MousePosition = Engine.Renderer != null?Engine.Renderer.ScaleMousePosition(pos) : pos;

                return(IntPtr.Zero);

            case WM.LBUTTONDOWN:
            case WM.RBUTTONDOWN:
            case WM.MBUTTONDOWN:
            case WM.XBUTTONDOWN:
            case WM.LBUTTONUP:
            case WM.RBUTTONUP:
            case WM.MBUTTONUP:
            case WM.XBUTTONUP:

                var mouseKey   = MouseKey.Unknown;
                var buttonDown = false;
                mouseKey = msg switch
                {
                    WM.LBUTTONDOWN => MouseKey.Left,
                    WM.LBUTTONUP => MouseKey.Left,
                    WM.RBUTTONDOWN => MouseKey.Right,
                    WM.RBUTTONUP => MouseKey.Right,
                    WM.MBUTTONDOWN => MouseKey.Middle,
                    WM.MBUTTONUP => MouseKey.Middle,
                    _ => mouseKey
                };

                if (msg == WM.LBUTTONDOWN || msg == WM.RBUTTONDOWN ||
                    msg == WM.MBUTTONDOWN || msg == WM.XBUTTONDOWN)
                {
                    buttonDown = true;
                }

                var nonePressed = true;
                foreach (bool keyDown in _mouseKeys)
                {
                    if (keyDown)
                    {
                        nonePressed = false;
                    }
                }

                if (nonePressed)
                {
                    User32.SetCapture(win.Handle);
                }

                UpdateMouseKeyStatus(mouseKey, buttonDown);

                nonePressed = true;
                foreach (bool keyDown in _mouseKeys)
                {
                    if (keyDown)
                    {
                        nonePressed = false;
                    }
                }

                if (nonePressed)
                {
                    User32.ReleaseCapture();
                }

                if (msg == WM.XBUTTONDOWN || msg == WM.XBUTTONUP)
                {
                    return((IntPtr)1);
                }

                return(IntPtr.Zero);

            case WM.MOUSEWHEEL:

                var scrollAmount = (short)NativeHelpers.HiWord((ulong)wParam);
                UpdateScroll(scrollAmount / 120f);

                return(IntPtr.Zero);
            }

            return(User32.DefWindowProc(hWnd, msg, wParam, lParam));
        }