Пример #1
0
        protected override Vector2 GetPosition()
        {
            var p = new Point();

            User32.ClientToScreen(_windowHandle, ref p);
            return(new Vector2(p.X, p.Y));
        }
Пример #2
0
        protected override void SetSize(Vector2 value)
        {
            // Scale the rect, and set it.
            Rect r      = GetFullWindowRect((int)value.X, (int)value.Y);
            int  width  = r.Right - r.Left;
            int  height = r.Bottom - r.Top;

            // Center on the monitor.
            Monitor monitor = GetMonitorOfWindow();

            if (monitor == null)
            {
                Engine.Log.Warning("No monitor attached?", MessageSource.Win32);
                return;
            }

            Vector2 center = monitor.Position + new Vector2(monitor.Width, monitor.Height) / 2 - new Vector2(width, height) / 2;

            User32.SetWindowPos(_windowHandle, (IntPtr)HwndZOrder.HWND_NOTOPMOST,
                                (int)center.X + r.Left,
                                (int)center.Y + r.Top,
                                r.Right - r.Left,
                                r.Bottom - r.Top,
                                WindowPositionFlags.SWP_NOACTIVATE | WindowPositionFlags.SWP_SHOWWINDOW
                                );
        }
        private void RegisterWindowClass()
        {
            _wndProcDelegate = WndProc;
            var wc = new WindowClassEx
            {
                Styles         = WindowClassStyles.CS_HREDRAW | WindowClassStyles.CS_VREDRAW | WindowClassStyles.CS_OWNDC,
                WindowProc     = _wndProcDelegate,
                InstanceHandle = Kernel32.GetModuleHandle(null),
                CursorHandle   = User32.LoadCursor(IntPtr.Zero, (IntPtr)SystemCursor.IDC_ARROW),
                ClassName      = CLASS_NAME
            };

            wc.Size = (uint)Marshal.SizeOf(wc);

            // Load user icon - if any.
            wc.IconHandle = User32.LoadImage(Kernel32.GetModuleHandle(null), "#32512", ResourceImageType.IMAGE_ICON, 0, 0, LoadResourceFlags.LR_DEFAULTSIZE | LoadResourceFlags.LR_SHARED);
            if (wc.IconHandle == IntPtr.Zero)
            {
                Kernel32.SetLastError(0);

                // None loaded - load default.
                wc.IconHandle = User32.LoadImage(IntPtr.Zero, (IntPtr)SystemIcon.IDI_APPLICATION, ResourceImageType.IMAGE_ICON, 0, 0, LoadResourceFlags.LR_DEFAULTSIZE | LoadResourceFlags.LR_SHARED);
            }

            ushort windowClass = User32.RegisterClassEx(ref wc);

            if (windowClass == 0)
            {
                CheckError("Win32: Failed to register window class.", true);
            }

            CheckError("Win32: Could not register class.");
        }
Пример #4
0
        /// <inheritdoc />
        protected override bool UpdatePlatform()
        {
            // Shift keys on windows tend to "stick"
            // When one key is held, the other doesn't receive down events, and an up event
            // is sent only to the latter one. To work around this manually query the status of both shift keys every tick.
            if (IsFocused)
            {
                KeyState lShift = User32.GetAsyncKeyState(VirtualKey.LSHIFT);
                UpdateKeyStatus(Key.LeftShift, lShift.IsPressed);
                KeyState rShift = User32.GetAsyncKeyState(VirtualKey.RSHIFT);
                UpdateKeyStatus(Key.RightShift, rShift.IsPressed);
            }

            while (User32.PeekMessage(out Message msg, IntPtr.Zero, 0, 0, PeekMessageFlags.PM_REMOVE))
            {
                // Generated by task manager and stuff like that.
                // The WM_QUIT message is not associated with a window and therefore will never be received through a window's window procedure.
                if (msg.Value == WM.QUIT)
                {
                    IsOpen = false;
                    return(false);
                }

                User32.TranslateMessage(ref msg);
                User32.DispatchMessage(ref msg);
            }

            if (HostPaused)
            {
                User32.WaitMessage();
            }

            return(true);
        }
Пример #5
0
        protected override void UpdateDisplayMode()
        {
            // Get the monitor
            Monitor monitor = GetMonitorOfWindow();

            if (monitor == null)
            {
                Engine.Log.Warning("No monitor attached?", MessageSource.Win32);
                return;
            }

            switch (_mode)
            {
            case DisplayMode.Windowed:
                WindowStyles style = DetermineWindowStyle();
                IntPtr       res   = User32.SetWindowLongPtr(_windowHandle, WindowLongFlags.GWL_STYLE, (IntPtr)style);
                if (res == IntPtr.Zero)
                {
                    CheckError("Couldn't change display mode to windowed.", true);
                }

                if (_windowModeSize != null)
                {
                    Size            = (Vector2)_windowModeSize;
                    _windowModeSize = null;
                }

                // Center window on screen. (This will also apply the SetWindowLongPtr changes, and remove the topmost status when exiting out of fullscreen)
                Position = monitor.Position + (new Vector2(monitor.Width, monitor.Height) / 2 - Size / 2);

                break;

            case DisplayMode.Fullscreen:
                IntPtr resp = User32.SetWindowLongPtr(_windowHandle, WindowLongFlags.GWL_STYLE, (IntPtr)FULLSCREEN_STYLE);
                if (resp == IntPtr.Zero)
                {
                    CheckError("Couldn't change display mode to fullscreen, couldn't apply window style.", true);
                    return;
                }

                bool successful = User32.SetWindowPos(
                    _windowHandle, (IntPtr)HwndZOrder.HWND_NOTOPMOST,
                    (int)monitor.Position.X, (int)monitor.Position.Y,
                    monitor.Width, monitor.Height,
                    WindowPositionFlags.SWP_NOACTIVATE | WindowPositionFlags.SWP_NOCOPYBITS | WindowPositionFlags.SWP_FRAMECHANGED
                    );
                if (!successful)
                {
                    CheckError("Couldn't change display mode to fullscreen, couldn't apply window rect.", true);
                }

                // Center cursor on screen/window.
                User32.SetCursorPos((int)(monitor.Position.X + monitor.Width / 2), (int)(monitor.Position.Y + monitor.Height / 2));

                break;
            }
        }
Пример #6
0
 public static void GetFullWindowRect(WindowStyles style, WindowExStyles styleEx, uint dpi, ref Rect rect)
 {
     if (IsWindows10AnniversaryUpdateOrGreaterWin32)
     {
         User32.AdjustWindowRectExForDpi(ref rect, style, false, styleEx, dpi);
     }
     else
     {
         User32.AdjustWindowRectEx(ref rect, style, false, styleEx);
     }
 }
Пример #7
0
        /// <summary>
        /// Transform the provided rectangle to fit the scale and position of the window.
        /// </summary>
        /// <param name="rect">The rect to transform.</param>
        /// <returns>The transformed rectangle.</returns>
        public Rect GetFullWindowRect(ref Rect rect)
        {
            uint dpi = DEFAULT_DPI;

            if (IsWindows10AnniversaryUpdateOrGreaterWin32)
            {
                dpi = User32.GetDpiForWindow(_windowHandle);
            }

            GetFullWindowRect(DetermineWindowStyle(), WindowExStyles.WS_EX_APPWINDOW, dpi, ref rect);
            return(rect);
        }
        /// <summary>
        /// Updates key names according to the current keyboard layout.
        /// </summary>
        private void PopulateKeyNames()
        {
            var state = new byte[256];

            // Initialize the key names array.
            _keyNames = new string[_scanCodes.Length];

            for (var key = (int)Key.Space; key < (int)Key.Last; key++)
            {
                uint vk;

                int scanCode = _scanCodes[key];
                if (scanCode == -1)
                {
                    continue;
                }

                if (key >= (int)Key.Kp0 && key <= (int)Key.KpAdd)
                {
                    uint[] vks =
                    {
                        (uint)VirtualKey.NUMPAD0,  (uint)VirtualKey.NUMPAD1,  (uint)VirtualKey.NUMPAD2, (uint)VirtualKey.NUMPAD3,
                        (uint)VirtualKey.NUMPAD4,  (uint)VirtualKey.NUMPAD5,  (uint)VirtualKey.NUMPAD6, (uint)VirtualKey.NUMPAD7,
                        (uint)VirtualKey.NUMPAD8,  (uint)VirtualKey.NUMPAD9,  (uint)VirtualKey.DECIMAL, (uint)VirtualKey.DIVIDE,
                        (uint)VirtualKey.MULTIPLY, (uint)VirtualKey.SUBTRACT, (uint)VirtualKey.ADD
                    };

                    vk = vks[key - (int)Key.Kp0];
                }
                else
                {
                    vk = User32.MapVirtualKey((uint)scanCode, VirtualKeyMapType.MAPVK_VSC_TO_VK);
                }

                var chars  = new StringBuilder(16);
                int length = User32.ToUnicode(vk, (uint)scanCode, state, chars, chars.Capacity, 0);
                if (length == -1)
                {
                    length = User32.ToUnicode(vk, (uint)scanCode, state, chars, chars.Capacity, 0);
                }

                if (length < 1)
                {
                    continue;
                }

                var keyName = new char[5];
                Kernel32.WideCharToMultiByte(CodePage.CpUtf8, 0, chars, 1, keyName, keyName.Length, IntPtr.Zero, out bool _);

                _keyNames[key] = NativeHelpers.StringFromNullTerminated(keyName);
            }
        }
Пример #9
0
        public Win32Monitor(DisplayDeviceW adapter, DisplayDeviceW?display)
        {
            Name        = display != null ? display.Value.DeviceString : adapter.DeviceString;
            AdapterName = adapter.DeviceName;
            DeviceName  = display == null ? "<<Unknown Device>>" : display.Value.DeviceName;
            Debug.Assert(Name != null);

            var dm = new DeviceMode();

            dm.dmSize = (short)Marshal.SizeOf(dm);
            User32.EnumDisplaySettingsW(adapter.DeviceName.PadRight(32, '\0'), (int)DisplaySettings.CurrentSettings, ref dm);
            Win32Platform.CheckError("Enumerating display settings.");

            Width  = dm.dmPelsWidth;
            Height = dm.dmPelsHeight;

            IntPtr dc = Gdi32.CreateDCW("DISPLAY", adapter.DeviceName, null, IntPtr.Zero);

            Debug.Assert(dc != IntPtr.Zero);

            if (Win32Platform.IsWindows81OrGreater)
            {
                WidthPhysical  = Gdi32.GetDeviceCaps(dc, DeviceCap.HorizontalSize);
                HeightPhysical = Gdi32.GetDeviceCaps(dc, DeviceCap.VertSize);
            }
            else
            {
                WidthPhysical  = (int)(dm.dmPelsWidth * 25.4f / Gdi32.GetDeviceCaps(dc, DeviceCap.LogPixelsX));
                HeightPhysical = (int)(dm.dmPelsHeight * 25.4f / Gdi32.GetDeviceCaps(dc, DeviceCap.LogPixelsY));
            }

            Gdi32.DeleteDC(dc);

            if ((adapter.StateFlags & DisplayDeviceStateFlags.ModesPruned) != 0)
            {
                ModesPruned = true;
            }

            var rect = new Rect
            {
                Left   = dm.dmPosition.X,
                Top    = dm.dmPosition.Y,
                Right  = dm.dmPosition.X + dm.dmPelsWidth,
                Bottom = dm.dmPosition.Y + dm.dmPelsHeight
            };

            User32.EnumDisplayMonitors(IntPtr.Zero, ref rect, MonitorCallback, null);
            Win32Platform.CheckError("Creating monitor.");
        }
        /// <inheritdoc />
        public override void DisplayMessageBox(string message)
        {
            IntPtr parentWindow = IntPtr.Zero;

            if (Window != null)
            {
                parentWindow = ((Win32Window)Window).Handle;
            }
            else if (HelperWindowHandle != IntPtr.Zero)
            {
                parentWindow = HelperWindowHandle;
            }

            User32.MessageBox(parentWindow, message, "Something went wrong!", (uint)(0x00000000L | 0x00000010L));
        }
        /// <summary>
        /// Convert wParam and lParam to a key.
        /// </summary>
        private Key TranslateKey(ulong wParam, ulong lParam)
        {
            switch (wParam)
            {
            // Control keys require special handling.
            case (uint)VirtualKey.CONTROL when(lParam& 0x01000000) != 0:
                return(Key.RightControl);

            case (uint)VirtualKey.CONTROL:
            {
                uint time = User32.GetMessageTime();

                // HACK: Alt Gr sends Left Ctrl and then Right Alt in close sequence
                //       We only want the Right Alt message, so if the next message is
                //       Right Alt we ignore this (synthetic) Left Ctrl message
                if (!User32.PeekMessage(out Message next, IntPtr.Zero, 0, 0, PeekMessageFlags.PM_NOREMOVE))
                {
                    return(Key.LeftControl);
                }
                if (next.Value != WM.KEYDOWN && next.Value != WM.SYSKEYDOWN && next.Value != WM.KEYUP && next.Value != WM.SYSKEYUP)
                {
                    return(Key.LeftControl);
                }
                if ((uint)next.WParam == (uint)VirtualKey.MENU && ((uint)next.LParam & 0x01000000) != 0 && next.Time == time)
                {
                    // Next message is Right Alt down so discard this
                    return(Key.Unknown);
                }

                return(Key.LeftControl);
            }

            // IME notifies that keys have been filtered by setting the virtual
            // key-code to VK_PROCESSKEY
            case (uint)VirtualKey.PROCESSKEY:
                return(Key.Unknown);
            }

            int index = NativeHelpers.HiWord(lParam) & 0x1FF;

            if (index < 0 || index >= _keyCodes.Length)
            {
                return(Key.Unknown);
            }
            return(_keyCodes[index]);
        }
Пример #12
0
        protected override void SetPosition(Vector2 position)
        {
            if (DisplayMode != DisplayMode.Windowed)
            {
                return;
            }

            // Get the size and scale it.
            Vector2 size = Size;
            Rect    rect = GetFullWindowRect((int)size.X, (int)size.Y);

            // Set the size and position.
            User32.SetWindowPos(_windowHandle, (IntPtr)HwndZOrder.HWND_NOTOPMOST,
                                (int)position.X + rect.Left,
                                (int)position.Y + rect.Top,
                                0,
                                0,
                                WindowPositionFlags.SWP_NOACTIVATE | WindowPositionFlags.SWP_NOCOPYBITS | WindowPositionFlags.SWP_SHOWWINDOW | WindowPositionFlags.SWP_NOSIZE);
        }
Пример #13
0
        public static void GetMonitorContentScale(IntPtr monitor, out float scaleX, out float scaleY)
        {
            uint xDpi, yDpi;

            if (Win32Platform.IsWindows81OrGreater)
            {
                ShCore.GetDpiForMonitor(monitor, MonitorDpiType.MDT_EFFECTIVE_DPI, out xDpi, out yDpi);
            }
            else
            {
                IntPtr dc = User32.GetDC(IntPtr.Zero);
                xDpi = (uint)Gdi32.GetDeviceCaps(dc, DeviceCap.LogPixelsX);
                yDpi = (uint)Gdi32.GetDeviceCaps(dc, DeviceCap.LogPixelsY);
                User32.ReleaseDC(IntPtr.Zero, dc);
            }

            scaleX = xDpi / (float)Win32Platform.DEFAULT_DPI;
            scaleY = yDpi / (float)Win32Platform.DEFAULT_DPI;
        }
        /// <inheritdoc />
        protected override bool UpdatePlatform()
        {
            // Update input.

            // NOTE: Shift keys on Windows tend to "stick" when both are pressed as
            //       no key up message is generated by the first key release
            //       The other half of this is in the handling of WM_KEYUP
            // HACK: Query actual key state and synthesize release events as needed
            KeyState lShift = User32.GetAsyncKeyState(VirtualKey.LSHIFT);
            KeyState rShift = User32.GetAsyncKeyState(VirtualKey.RSHIFT);

            // Check if it was down, but no longer is.
            if (_keys[(short)Key.LeftShift] && lShift.Value != 0)
            {
                UpdateKeyStatus(Key.LeftShift, false);
            }
            if (_keys[(short)Key.RightShift] && rShift.Value != 0)
            {
                UpdateKeyStatus(Key.RightShift, false);
            }

            while (User32.PeekMessage(out Message msg, IntPtr.Zero, 0, 0, PeekMessageFlags.PM_REMOVE))
            {
                // Things like the task manager will generate this message.
                if (msg.Value == WM.QUIT)
                {
                    IsOpen = false;
                    return(false);
                }

                User32.TranslateMessage(ref msg);
                User32.DispatchMessage(ref msg);
            }

            // Check if focused.
            if (!IsFocused && !Engine.Configuration.DebugMode)
            {
                User32.WaitMessage();
            }

            return(true);
        }
        private void CreateHelperWindow()
        {
            HelperWindowHandle = User32.CreateWindowEx(
                WindowExStyles.WS_EX_OVERLAPPEDWINDOW,
                CLASS_NAME,
                "Emotion Helper Window",
                WindowStyles.WS_CLIPSIBLINGS | WindowStyles.WS_CLIPCHILDREN,
                0, 0, 100, 100,
                IntPtr.Zero, IntPtr.Zero,
                Kernel32.GetModuleHandle(null),
                IntPtr.Zero
                );

            if (HelperWindowHandle == IntPtr.Zero)
            {
                CheckError("Win32: Failed to create helper window.", true);
            }

            // HACK: The command to the first ShowWindow call is ignored if the parent
            //       process passed along a STARTUPINFO, so clear that with a no-op call
            User32.ShowWindow(HelperWindowHandle, ShowWindowCommands.SW_HIDE);

            // Register for HID device notifications
            var dbi = new DevBroadcastDeviceInterfaceW();

            dbi.DbccSize              = (uint)Marshal.SizeOf(dbi);
            dbi.DbccDeviceType        = DeviceType.DeviceInterface;
            dbi.DbccClassGuid         = User32Guids.GuidDevInterfaceHid;
            _deviceNotificationHandle = User32.RegisterDeviceNotificationW(HelperWindowHandle, ref dbi, DeviceNotificationFlags.WindowHandle);

            CheckError("Registering for device notifications.");

            while (User32.PeekMessage(out Message msg, HelperWindowHandle, 0, 0, PeekMessageFlags.PM_REMOVE))
            {
                User32.TranslateMessage(ref msg);
                User32.DispatchMessage(ref msg);
            }

            Kernel32.SetLastError(0);

            CheckError("Creating helper window.");
        }
Пример #16
0
        private bool MonitorCallback(IntPtr hMonitor, IntPtr hdc, ref Rect rect, object dwData)
        {
            var monitorInfo = new MonitorInfoEx();

            monitorInfo.Size = (uint)Marshal.SizeOf(monitorInfo);

            // Try to get monitor info.
            if (!User32.GetMonitorInfo(hMonitor, ref monitorInfo))
            {
                return(false);
            }
            // Check if the adapter name matches, in which case this is the handle to this monitor.
            if (monitorInfo.SzDevice == AdapterName)
            {
                Handle = hMonitor;
            }

            Position = new Vector2(monitorInfo.MonitorRect.Left, monitorInfo.MonitorRect.Top);

            return(true);
        }
        /// <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));
        }
        /// <summary>
        /// Polls and updates the statuses of connected monitors.
        /// </summary>
        private void PollMonitors()
        {
            // All monitors are considered inactive until proven otherwise.
            var inactive = new List <Monitor>();

            inactive.AddRange(Monitors);

            for (uint adapterIndex = 0;; adapterIndex++)
            {
                var first = false;

                var adapter = new DisplayDeviceW();
                adapter.Cb = (uint)Marshal.SizeOf(adapter);

                if (!User32.EnumDisplayDevicesW(null, adapterIndex, ref adapter, 0))
                {
                    break;
                }

                // If the adapter is inactive - continue;
                if ((adapter.StateFlags & DisplayDeviceStateFlags.Active) == 0)
                {
                    continue;
                }

                if ((adapter.StateFlags & DisplayDeviceStateFlags.PrimaryDevice) != 0)
                {
                    first = true;
                }

                uint displayIndex;
                for (displayIndex = 0;; displayIndex++)
                {
                    var display = new DisplayDeviceW();
                    display.Cb = (uint)Marshal.SizeOf(display);

                    if (!User32.EnumDisplayDevicesW(adapter.DeviceName, displayIndex, ref display, 0))
                    {
                        break;
                    }

                    // If not active - continue;
                    if ((display.StateFlags & DisplayDeviceStateFlags.Active) == 0)
                    {
                        continue;
                    }

                    // If active - remove from inactive list.
                    // If something was removed, that means this display exists in the monitor array.
                    if (inactive.RemoveAll(x => x.Name == display.DeviceName) > 0)
                    {
                        continue;
                    }

                    UpdateMonitor(new Win32Monitor(adapter, display), true, first);
                }

                // HACK: If an active adapter does not have any display devices (as sometimes happens), add it directly as a monitor.
                if (displayIndex != 0)
                {
                    continue;
                }

                // Remove self from inactive list.
                if (inactive.RemoveAll(x => x.Name == adapter.DeviceName) > 0)
                {
                    continue;
                }

                UpdateMonitor(new Win32Monitor(adapter, null), true, first);
            }

            foreach (Monitor inactiveMonitor in inactive)
            {
                UpdateMonitor(inactiveMonitor, false, false);
            }
        }
Пример #19
0
 public void FocusWindow()
 {
     User32.BringWindowToTop(_windowHandle);
     User32.SetForegroundWindow(_windowHandle);
     User32.SetFocus(_windowHandle);
 }
Пример #20
0
 protected override Vector2 GetSize()
 {
     User32.GetClientRect(_windowHandle, out Rect rect);
     return(new Vector2(rect.Right, rect.Bottom));
 }
        /// <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;
        }
Пример #22
0
        /// <inheritdoc />
        protected override void SetupInternal(Configurator config)
        {
            IsWindows7OrGreater = IsWindowsVersionOrGreaterWin32(
                NativeHelpers.HiByte((ushort)NtDll.WinVer.Win32WinNTWin7),
                NativeHelpers.LoByte((ushort)NtDll.WinVer.Win32WinNTWin7),
                0);
            IsWindows8OrGreater = IsWindowsVersionOrGreaterWin32(
                NativeHelpers.HiByte((ushort)NtDll.WinVer.Win32WinNTWin8),
                NativeHelpers.LoByte((ushort)NtDll.WinVer.Win32WinNTWin8),
                0);
            IsWindows81OrGreater = IsWindowsVersionOrGreaterWin32(
                NativeHelpers.HiByte((ushort)NtDll.WinVer.Win32WinNTWinBlue),
                NativeHelpers.LoByte((ushort)NtDll.WinVer.Win32WinNTWinBlue),
                0);
            IsWindows10AnniversaryUpdateOrGreaterWin32 = IsWindows10BuildOrGreaterWin32(14393);
            IsWindows10CreatorsUpdateOrGreaterWin32    = IsWindows10BuildOrGreaterWin32(15063);

            var windowsVersionFlags = new List <string>();

            if (IsWindows7OrGreater)
            {
                windowsVersionFlags.Add(nameof(IsWindows7OrGreater));
            }
            if (IsWindows8OrGreater)
            {
                windowsVersionFlags.Add(nameof(IsWindows8OrGreater));
            }
            if (IsWindows81OrGreater)
            {
                windowsVersionFlags.Add(nameof(IsWindows81OrGreater));
            }
            if (IsWindows10AnniversaryUpdateOrGreaterWin32)
            {
                windowsVersionFlags.Add(nameof(IsWindows10AnniversaryUpdateOrGreaterWin32));
            }
            if (IsWindows10CreatorsUpdateOrGreaterWin32)
            {
                windowsVersionFlags.Add(nameof(IsWindows10CreatorsUpdateOrGreaterWin32));
            }
            Engine.Log.Trace(string.Join(", ", windowsVersionFlags), MessageSource.Win32);

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

            // todo: load libraries - if any, probably XInput?

            // Initialize audio.
            AudioContext ctx = null;

#if OpenAL
            ctx ??= OpenALAudioAdapter.TryCreate(this);
#endif
            ctx ??= WasApiAudioContext.TryCreate(this);
            ctx ??= new NullAudioContext();
            Audio = ctx;
            Engine.Log.Trace("Audio init complete.", MessageSource.Win32);

            PopulateKeyCodes();
            RegisterWindowClass();
            CreateHelperWindow();
            PollMonitors();
            Engine.Log.Trace("Platform helpers created.", MessageSource.Win32);

            var windowInitialSize = new Rect
            {
                Right  = (int)config.HostSize.X,
                Bottom = (int)config.HostSize.Y
            };
            GetFullWindowRect(DEFAULT_WINDOW_STYLE, DEFAULT_WINDOW_STYLE_EX, DEFAULT_DPI, ref windowInitialSize);
            int initialWidth  = windowInitialSize.Right - windowInitialSize.Left;
            int initialHeight = windowInitialSize.Bottom - windowInitialSize.Top;

            WindowStyles windowStyle = DEFAULT_WINDOW_STYLE;
            if (config.HiddenWindow)
            {
                windowStyle &= ~WindowStyles.WS_VISIBLE;
                windowStyle &= ~WindowStyles.WS_MINIMIZE;

                // This will override the hide otherwise
                config.InitialDisplayMode = DisplayMode.Initial;
            }

            IntPtr windowHandle = User32.CreateWindowEx(
                DEFAULT_WINDOW_STYLE_EX,
                CLASS_NAME,
                config.HostTitle,
                windowStyle,
                (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 (windowHandle == IntPtr.Zero)
            {
                CheckError("Couldn't create window.", true);
                return;
            }

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

            string[] args       = Environment.GetCommandLineArgs();
            bool     forceAngle = CommandLineParser.FindArgument(args, "angle", out string _);
            bool     forceMesa  = CommandLineParser.FindArgument(args, "software", out string _);

            // Create graphics context.

            if (!forceAngle && !forceMesa)
            {
                try
                {
                    var wgl = new WglGraphicsContext();
                    wgl.Init(User32.GetDC(_helperWindowHandle), windowHandle, this);
                    if (wgl.Valid)
                    {
                        Context = wgl;
                    }
                }
                catch (Exception ex)
                {
                    Engine.Log.Warning($"Couldn't create WGL context, falling back if possible.\n{ex}", MessageSource.Win32);
                }
            }

#if ANGLE
            if (Context == null && !forceMesa)
            {
                try
                {
                    var egl = new EglGraphicsContext();
                    egl.Init(User32.GetDC(windowHandle), windowHandle, this);
                    if (egl.Valid)
                    {
                        Context = egl;
                    }
                }
                catch (Exception ex)
                {
                    Engine.Log.Warning($"Couldn't create EGL context, falling back if possible.\n{ex}", MessageSource.Win32);
                }
            }
#endif

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

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

            // 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(windowHandle);
            GetFullWindowRect(ref rect);
            User32.SetWindowPos(_windowHandle, IntPtr.Zero,
                                rect.Left, rect.Top,
                                rect.Right - rect.Left, rect.Bottom - rect.Top,
                                WindowPositionFlags.SWP_NOACTIVATE | WindowPositionFlags.SWP_NOZORDER);

            _windowHandle = windowHandle;
        }
Пример #23
0
        private WindowProc _wndProcDelegate; // This needs to be assigned so the garbage collector doesn't collect it.

        /// <summary>
        /// Handler for messages.
        /// </summary>
        private unsafe IntPtr WndProc(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam)
        {
            if (_windowHandle == IntPtr.Zero)
            {
                // 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 = 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)_config.RenderSize.X + offX;
                mmi->MinTrackSize.Y = (int)_config.RenderSize.Y + offY;

                return(IntPtr.Zero);

            case WM.SIZE:

                int width  = NativeHelpers.LoWord((uint)lParam);
                int height = NativeHelpers.HiWord((uint)lParam);
                Resized(new Vector2(width, height));

                return(IntPtr.Zero);

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

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

            case WM.SYSCOMMAND:

                switch ((int)wParam & 0xfff0)
                {
                case (int)SysCommand.SC_SCREENSAVE:
                case (int)SysCommand.SC_MONITORPOWER:
                    if (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.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);
                }

                UpdateTextInput((char)wParam);
                break;

            case WM.KEYDOWN:
            case WM.SYSKEYDOWN:
            case WM.KEYUP:
            case WM.SYSKEYUP:
                var virtualKey = (VirtualKey)wParam;
                var lParamLong = (ulong)lParam;

                bool up  = ((lParamLong >> 31) & 1) != 0;
                Key  key = TranslateKey(virtualKey, lParamLong);
                if (key == Key.Unknown)
                {
                    break;
                }

                // Don't handle shift keys. Check UpdatePlatform() for more info.
                if (virtualKey == VirtualKey.SHIFT)
                {
                    break;
                }

                UpdateKeyStatus(key, !up);
                break;

            case WM.MOUSEMOVE:

                int x = NativeHelpers.LoWordS((uint)lParam);
                int y = NativeHelpers.HiWordS((uint)lParam);
                MousePosition = new Vector2(x, y);
                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:

                ushort keySpecifier = NativeHelpers.HiWord((ulong)wParam);
                var    mouseKey     = Key.Unknown;
                var    buttonDown   = false;
                mouseKey = msg switch
                {
                    WM.LBUTTONDOWN => Key.MouseKeyLeft,
                    WM.LBUTTONUP => Key.MouseKeyLeft,
                    WM.RBUTTONDOWN => Key.MouseKeyRight,
                    WM.RBUTTONUP => Key.MouseKeyRight,
                    WM.MBUTTONDOWN => Key.MouseKeyMiddle,
                    WM.MBUTTONUP => Key.MouseKeyMiddle,
                    WM.XBUTTONDOWN when keySpecifier == 1 => Key.MouseKey4,
                    WM.XBUTTONUP when keySpecifier == 1 => Key.MouseKey4,
                    WM.XBUTTONDOWN when keySpecifier == 2 => Key.MouseKey5,
                    WM.XBUTTONUP when keySpecifier == 2 => Key.MouseKey5,

                    _ => mouseKey
                };

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

                var nonePressed = true;
                for (int i = (int)Key.MouseKeyStart + 1; i < (int)Key.MouseKeyEnd; i++)
                {
                    if (!_keys[i])
                    {
                        continue;
                    }
                    nonePressed = false;
                    break;
                }

                if (nonePressed)
                {
                    User32.SetCapture(_windowHandle);
                }

                UpdateKeyStatus(mouseKey, buttonDown);

                nonePressed = true;
                for (int i = (int)Key.MouseKeyStart + 1; i < (int)Key.MouseKeyEnd; i++)
                {
                    if (!_keys[i])
                    {
                        continue;
                    }
                    nonePressed = false;
                    break;
                }

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

                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));
        }
Пример #24
0
        public void GetWindowContentScale(out float scaleX, out float scaleY)
        {
            IntPtr monitor = User32.MonitorFromWindow(_windowHandle, MonitorFlag.MONITOR_DEFAULTTONEAREST);

            Win32Monitor.GetMonitorContentScale(monitor, out scaleX, out scaleY);
        }