diff options
Diffstat (limited to 'platform/windows/display_server_windows.cpp')
-rw-r--r-- | platform/windows/display_server_windows.cpp | 404 |
1 files changed, 307 insertions, 97 deletions
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index c7955ebf31..93cab85441 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -84,6 +84,7 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const { case FEATURE_NATIVE_ICON: case FEATURE_SWAP_BUFFERS: case FEATURE_KEEP_SCREEN_ON: + case FEATURE_TEXT_TO_SPEECH: return true; default: return false; @@ -133,6 +134,41 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) { } } +bool DisplayServerWindows::tts_is_speaking() const { + ERR_FAIL_COND_V(!tts, false); + return tts->is_speaking(); +} + +bool DisplayServerWindows::tts_is_paused() const { + ERR_FAIL_COND_V(!tts, false); + return tts->is_paused(); +} + +Array DisplayServerWindows::tts_get_voices() const { + ERR_FAIL_COND_V(!tts, Array()); + return tts->get_voices(); +} + +void DisplayServerWindows::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) { + ERR_FAIL_COND(!tts); + tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt); +} + +void DisplayServerWindows::tts_pause() { + ERR_FAIL_COND(!tts); + tts->pause(); +} + +void DisplayServerWindows::tts_resume() { + ERR_FAIL_COND(!tts); + tts->resume(); +} + +void DisplayServerWindows::tts_stop() { + ERR_FAIL_COND(!tts); + tts->stop(); +} + void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) { _THREAD_SAFE_METHOD_ @@ -150,7 +186,7 @@ DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode() const { return mouse_mode; } -void DisplayServerWindows::mouse_warp_to_position(const Point2i &p_to) { +void DisplayServerWindows::warp_mouse(const Point2i &p_position) { _THREAD_SAFE_METHOD_ if (!windows.has(last_focused_window)) { @@ -158,12 +194,12 @@ void DisplayServerWindows::mouse_warp_to_position(const Point2i &p_to) { } if (mouse_mode == MOUSE_MODE_CAPTURED) { - old_x = p_to.x; - old_y = p_to.y; + old_x = p_position.x; + old_y = p_position.y; } else { POINT p; - p.x = p_to.x; - p.y = p_to.y; + p.x = p_position.x; + p.y = p_position.y; ClientToScreen(windows[last_focused_window].hWnd, &p); SetCursorPos(p.x, p.y); @@ -231,7 +267,7 @@ String DisplayServerWindows::clipboard_get() const { String ret; if (!OpenClipboard(windows[last_focused_window].hWnd)) { ERR_FAIL_V_MSG("", "Unable to open clipboard."); - }; + } if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); @@ -240,8 +276,8 @@ String DisplayServerWindows::clipboard_get() const { if (ptr != nullptr) { ret = String::utf16((const char16_t *)ptr); GlobalUnlock(mem); - }; - }; + } + } } else if (IsClipboardFormatAvailable(CF_TEXT)) { HGLOBAL mem = GetClipboardData(CF_UNICODETEXT); @@ -250,9 +286,9 @@ String DisplayServerWindows::clipboard_get() const { if (ptr != nullptr) { ret.parse_utf8((const char *)ptr); GlobalUnlock(mem); - }; - }; - }; + } + } + } CloseClipboard(); @@ -422,16 +458,16 @@ static int QueryDpiForMonitor(HMONITOR hmon, _MonitorDpiType dpiType = MDT_Defau getDPIForMonitor = Shcore ? (GetDPIForMonitor_t)GetProcAddress(Shcore, "GetDpiForMonitor") : nullptr; if ((Shcore == nullptr) || (getDPIForMonitor == nullptr)) { - if (Shcore) + if (Shcore) { FreeLibrary(Shcore); + } Shcore = (HMODULE)INVALID_HANDLE_VALUE; } } UINT x = 0, y = 0; - HRESULT hr = E_FAIL; if (hmon && (Shcore != (HMODULE)INVALID_HANDLE_VALUE)) { - hr = getDPIForMonitor(hmon, dpiType /*MDT_Effective_DPI*/, &x, &y); + HRESULT hr = getDPIForMonitor(hmon, dpiType /*MDT_Effective_DPI*/, &x, &y); if (SUCCEEDED(hr) && (x > 0) && (y > 0)) { dpiX = (int)x; dpiY = (int)y; @@ -545,6 +581,9 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { wd.no_focus = true; } + if (p_flags & WINDOW_FLAG_POPUP_BIT) { + wd.is_popup = true; + } // Inherit icons from MAIN_WINDOW for all sub windows. HICON mainwindow_icon = (HICON)SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_GETICON, ICON_SMALL, 0); @@ -562,13 +601,14 @@ void DisplayServerWindows::show_window(WindowID p_id) { ERR_FAIL_COND(!windows.has(p_id)); WindowData &wd = windows[p_id]; + popup_open(p_id); if (p_id != MAIN_WINDOW_ID) { _update_window_style(p_id); } - ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window. - if (!wd.no_focus) { + ShowWindow(wd.hWnd, (wd.no_focus || wd.is_popup) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window. + if (!wd.no_focus && !wd.is_popup) { SetForegroundWindow(wd.hWnd); // Slightly higher priority. SetFocus(wd.hWnd); // Set keyboard focus. } @@ -580,6 +620,8 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window cannot be deleted."); + popup_close(p_window); + WindowData &wd = windows[p_window]; while (wd.transient_children.size()) { @@ -837,8 +879,8 @@ void DisplayServerWindows::window_set_exclusive(WindowID p_window, bool p_exclus if (wd.exclusive != p_exclusive) { wd.exclusive = p_exclusive; if (wd.transient_parent != INVALID_WINDOW_ID) { - WindowData &wd_parent = windows[wd.transient_parent]; if (wd.exclusive) { + WindowData &wd_parent = windows[wd.transient_parent]; SetWindowLongPtr(wd.hWnd, GWLP_HWNDPARENT, (LONG_PTR)wd_parent.hWnd); } else { SetWindowLongPtr(wd.hWnd, GWLP_HWNDPARENT, (LONG_PTR) nullptr); @@ -1018,6 +1060,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre r_style_ex = WS_EX_WINDOWEDGE; if (p_main_window) { r_style_ex |= WS_EX_APPWINDOW; + r_style |= WS_VISIBLE; } if (p_fullscreen || p_borderless) { @@ -1036,13 +1079,15 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre r_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; } } - if (!p_borderless) { - r_style |= WS_VISIBLE; - } if (p_no_activate_focus) { r_style_ex |= WS_EX_TOPMOST | WS_EX_NOACTIVATE; } + + if (!p_borderless && !p_no_activate_focus) { + r_style |= WS_VISIBLE; + } + r_style |= WS_CLIPCHILDREN | WS_CLIPSIBLINGS; r_style_ex |= WS_EX_ACCEPTFILES; } @@ -1056,12 +1101,16 @@ void DisplayServerWindows::_update_window_style(WindowID p_window, bool p_repain DWORD style = 0; DWORD style_ex = 0; - _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.no_focus, style, style_ex); + _get_window_style(p_window == MAIN_WINDOW_ID, wd.fullscreen, wd.multiwindow_fs, wd.borderless, wd.resizable, wd.maximized, wd.no_focus || wd.is_popup, style, style_ex); SetWindowLongPtr(wd.hWnd, GWL_STYLE, style); SetWindowLongPtr(wd.hWnd, GWL_EXSTYLE, style_ex); - SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | (wd.no_focus ? SWP_NOACTIVATE : 0)); + if (icon.is_valid()) { + set_icon(icon); + } + + SetWindowPos(wd.hWnd, wd.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0)); if (p_repaint) { RECT rect; @@ -1212,6 +1261,7 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W wd.borderless = p_enabled; _update_window_style(p_window); _update_window_mouse_passthrough(p_window); + ShowWindow(wd.hWnd, (wd.no_focus || wd.is_popup) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window. } break; case WINDOW_FLAG_ALWAYS_ON_TOP: { ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID && p_enabled, "Transient windows can't become on top"); @@ -1225,6 +1275,11 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W wd.no_focus = p_enabled; _update_window_style(p_window); } break; + case WINDOW_FLAG_POPUP: { + ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup."); + ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened."); + wd.is_popup = p_enabled; + } break; case WINDOW_FLAG_MAX: break; } @@ -1251,6 +1306,9 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window case WINDOW_FLAG_NO_FOCUS: { return wd.no_focus; } break; + case WINDOW_FLAG_POPUP: { + return wd.is_popup; + } break; case WINDOW_FLAG_MAX: break; } @@ -1262,7 +1320,7 @@ void DisplayServerWindows::window_request_attention(WindowID p_window) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!windows.has(p_window)); - WindowData &wd = windows[p_window]; + const WindowData &wd = windows[p_window]; FLASHWINFO info; info.cbSize = sizeof(FLASHWINFO); @@ -1279,7 +1337,9 @@ void DisplayServerWindows::window_move_to_foreground(WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - SetForegroundWindow(wd.hWnd); + if (!wd.no_focus && !wd.is_popup) { + SetForegroundWindow(wd.hWnd); + } } bool DisplayServerWindows::window_can_draw(WindowID p_window) const { @@ -1326,8 +1386,9 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI wd.im_position = p_pos; HIMC himc = ImmGetContext(wd.hWnd); - if (himc == (HIMC)0) + if (himc == (HIMC)0) { return; + } COMPOSITIONFORM cps; cps.dwStyle = CFS_FORCE_POSITION; @@ -1433,7 +1494,7 @@ void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTra DeleteDC(hMainDC); } -void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { +void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) { _THREAD_SAFE_METHOD_ if (p_cursor.is_valid()) { @@ -1540,13 +1601,8 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh } } - if (hAndMask != nullptr) { - DeleteObject(hAndMask); - } - - if (hXorMask != nullptr) { - DeleteObject(hXorMask); - } + DeleteObject(hAndMask); + DeleteObject(hXorMask); memfree(buffer); DeleteObject(bitmap); @@ -1749,8 +1805,8 @@ void DisplayServerWindows::swap_buffers() { void DisplayServerWindows::set_native_icon(const String &p_filename) { _THREAD_SAFE_METHOD_ - FileAccess *f = FileAccess::open(p_filename, FileAccess::READ); - ERR_FAIL_COND_MSG(!f, "Cannot open file with icon '" + p_filename + "'."); + Ref<FileAccess> f = FileAccess::open(p_filename, FileAccess::READ); + ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file with icon '" + p_filename + "'."); ICONDIR *icon_dir = (ICONDIR *)memalloc(sizeof(ICONDIR)); int pos = 0; @@ -1836,7 +1892,6 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) { err = GetLastError(); ERR_FAIL_COND_MSG(err, "Error setting ICON_BIG: " + format_error_message(err) + "."); - memdelete(f); memdelete(icon_dir); } @@ -1844,9 +1899,11 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) { _THREAD_SAFE_METHOD_ ERR_FAIL_COND(!p_icon.is_valid()); - Ref<Image> icon = p_icon->duplicate(); - if (icon->get_format() != Image::FORMAT_RGBA8) { - icon->convert(Image::FORMAT_RGBA8); + if (icon != p_icon) { + icon = p_icon->duplicate(); + if (icon->get_format() != Image::FORMAT_RGBA8) { + icon->convert(Image::FORMAT_RGBA8); + } } int w = icon->get_width(); int h = icon->get_height(); @@ -1895,16 +1952,14 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) { void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) - // TODO disabling for now - //context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); #endif } DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const { _THREAD_SAFE_METHOD_ #if defined(VULKAN_ENABLED) - //TODO disabling for now - //return context_vulkan->get_vsync_mode(p_window); + return context_vulkan->get_vsync_mode(p_window); #endif return DisplayServer::VSYNC_ENABLED; } @@ -1974,7 +2029,7 @@ void DisplayServerWindows::_send_window_event(const WindowData &wd, WindowEvent } void DisplayServerWindows::_dispatch_input_events(const Ref<InputEvent> &p_event) { - ((DisplayServerWindows *)(get_singleton()))->_dispatch_input_event(p_event); + static_cast<DisplayServerWindows *>(get_singleton())->_dispatch_input_event(p_event); } void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) { @@ -1989,33 +2044,155 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event) Variant ret; Callable::CallError ce; + { + List<WindowID>::Element *E = popup_list.back(); + if (E && Object::cast_to<InputEventKey>(*p_event)) { + // Redirect keyboard input to active popup. + if (windows.has(E->get())) { + Callable callable = windows[E->get()].input_event_callback; + if (callable.is_valid()) { + callable.call((const Variant **)&evp, 1, ret, ce); + } + } + in_dispatch_input_event = false; + return; + } + } + Ref<InputEventFromWindow> event_from_window = p_event; if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) { // Send to a single window. - if (!windows.has(event_from_window->get_window_id())) { - in_dispatch_input_event = false; - ERR_FAIL_MSG("DisplayServerWindows: Invalid window id in input event."); - } - Callable callable = windows[event_from_window->get_window_id()].input_event_callback; - if (callable.is_null()) { - in_dispatch_input_event = false; - return; + if (windows.has(event_from_window->get_window_id())) { + Callable callable = windows[event_from_window->get_window_id()].input_event_callback; + if (callable.is_valid()) { + callable.call((const Variant **)&evp, 1, ret, ce); + } } - callable.call((const Variant **)&evp, 1, ret, ce); } else { // Send to all windows. for (const KeyValue<WindowID, WindowData> &E : windows) { const Callable callable = E.value.input_event_callback; - if (callable.is_null()) { - continue; + if (callable.is_valid()) { + callable.call((const Variant **)&evp, 1, ret, ce); } - callable.call((const Variant **)&evp, 1, ret, ce); } } in_dispatch_input_event = false; } +LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) { + DisplayServerWindows *ds_win = static_cast<DisplayServerWindows *>(DisplayServer::get_singleton()); + if (ds_win) { + return ds_win->MouseProc(code, wParam, lParam); + } else { + return ::CallNextHookEx(nullptr, code, wParam, lParam); + } +} + +DisplayServer::WindowID DisplayServerWindows::window_get_active_popup() const { + const List<WindowID>::Element *E = popup_list.back(); + if (E) { + return E->get(); + } else { + return INVALID_WINDOW_ID; + } +} + +void DisplayServerWindows::window_set_popup_safe_rect(WindowID p_window, const Rect2i &p_rect) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!windows.has(p_window)); + WindowData &wd = windows[p_window]; + wd.parent_safe_rect = p_rect; +} + +Rect2i DisplayServerWindows::window_get_popup_safe_rect(WindowID p_window) const { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_V(!windows.has(p_window), Rect2i()); + const WindowData &wd = windows[p_window]; + return wd.parent_safe_rect; +} + +void DisplayServerWindows::popup_open(WindowID p_window) { + _THREAD_SAFE_METHOD_ + + const WindowData &wd = windows[p_window]; + if (wd.is_popup) { + // Find current popup parent, or root popup if new window is not transient. + List<WindowID>::Element *C = nullptr; + List<WindowID>::Element *E = popup_list.back(); + while (E) { + if (wd.transient_parent != E->get() || wd.transient_parent == INVALID_WINDOW_ID) { + C = E; + E = E->prev(); + } else { + break; + } + } + if (C) { + _send_window_event(windows[C->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST); + } + + time_since_popup = OS::get_singleton()->get_ticks_msec(); + popup_list.push_back(p_window); + } +} + +void DisplayServerWindows::popup_close(WindowID p_window) { + _THREAD_SAFE_METHOD_ + + List<WindowID>::Element *E = popup_list.find(p_window); + while (E) { + List<WindowID>::Element *F = E->next(); + WindowID win_id = E->get(); + popup_list.erase(E); + + _send_window_event(windows[win_id], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST); + E = F; + } +} + +LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam) { + _THREAD_SAFE_METHOD_ + + uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_popup; + if (delta > 250) { + switch (wParam) { + case WM_NCLBUTTONDOWN: + case WM_NCRBUTTONDOWN: + case WM_NCMBUTTONDOWN: + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: { + MOUSEHOOKSTRUCT *ms = (MOUSEHOOKSTRUCT *)lParam; + Point2i pos = Point2i(ms->pt.x, ms->pt.y); + List<WindowID>::Element *C = nullptr; + List<WindowID>::Element *E = popup_list.back(); + // Find top popup to close. + while (E) { + // Popup window area. + Rect2i win_rect = Rect2i(window_get_position(E->get()), window_get_size(E->get())); + // Area of the parent window, which responsible for opening sub-menu. + Rect2i safe_rect = window_get_popup_safe_rect(E->get()); + if (win_rect.has_point(pos)) { + break; + } else if (safe_rect != Rect2i() && safe_rect.has_point(pos)) { + break; + } else { + C = E; + E = E->prev(); + } + } + if (C) { + _send_window_event(windows[C->get()], DisplayServerWindows::WINDOW_EVENT_CLOSE_REQUEST); + } + } break; + } + } + return ::CallNextHookEx(mouse_monitor, code, wParam, lParam); +} + // Our default window procedure to handle processing of window-related system messages/events. // Also known as DefProc or DefWindowProc. // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures @@ -2026,7 +2203,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } else { return DefWindowProcW(hWnd, uMsg, wParam, lParam); } - }; + } WindowID window_id = INVALID_WINDOW_ID; bool window_created = false; @@ -2048,6 +2225,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // Process window messages. switch (uMsg) { + case WM_MOUSEACTIVATE: { + if (windows[window_id].no_focus) { + return MA_NOACTIVATEANDEAT; // Do not activate, and discard mouse messages. + } else if (windows[window_id].is_popup) { + return MA_NOACTIVATE; // Do not activate, but process mouse messages. + } + } break; case WM_SETFOCUS: { windows[window_id].window_has_focus = true; last_focused_window = window_id; @@ -2131,8 +2315,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case SC_MONITORPOWER: // Monitor trying to enter powersave? return 0; // Prevent from happening. case SC_KEYMENU: - if ((lParam >> 16) <= 0) + if ((lParam >> 16) <= 0) { return 0; + } } } break; case WM_CLOSE: // Did we receive a close message? @@ -2164,8 +2349,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA return 0; } - if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize) + if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize) { OutputDebugString(TEXT("GetRawInputData does not return correct size !\n")); + } RAWINPUT *raw = (RAWINPUT *)lpb; @@ -2260,8 +2446,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA ScreenToClient(windows[window_id].hWnd, &coords); // Don't calculate relative mouse movement if we don't have focus in CAPTURED mode. - if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) + if (!windows[window_id].window_has_focus && mouse_mode == MOUSE_MODE_CAPTURED) { break; + } Ref<InputEventMouseMotion> mm; mm.instantiate(); @@ -2306,8 +2493,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y))); old_x = mm->get_position().x; old_y = mm->get_position().y; - if (windows[window_id].window_has_focus) + if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) { Input::get_singleton()->parse_input_event(mm); + } } return 0; } @@ -2447,7 +2635,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y))); old_x = mm->get_position().x; old_y = mm->get_position().y; - if (windows[window_id].window_has_focus) { + if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) { Input::get_singleton()->parse_input_event(mm); } @@ -2547,8 +2735,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y))); old_x = mm->get_position().x; old_y = mm->get_position().y; - if (windows[window_id].window_has_focus) + if (windows[window_id].window_has_focus || window_get_active_popup() == window_id) { Input::get_singleton()->parse_input_event(mm); + } } break; case WM_LBUTTONDOWN: @@ -2694,8 +2883,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (uMsg != WM_MOUSEWHEEL && uMsg != WM_MOUSEHWHEEL) { if (mb->is_pressed()) { - if (++pressrc > 0 && mouse_mode != MOUSE_MODE_CAPTURED) + if (++pressrc > 0 && mouse_mode != MOUSE_MODE_CAPTURED) { SetCapture(hWnd); + } } else { if (--pressrc <= 0) { if (mouse_mode != MOUSE_MODE_CAPTURED) { @@ -2705,7 +2895,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } } else { - // For reasons unknown to mankind, wheel comes in screen coordinates. + // For reasons unknown to humanity, wheel comes in screen coordinates. POINT coords; coords.x = mb->get_position().x; coords.y = mb->get_position().y; @@ -2770,13 +2960,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA window.width = window_client_rect.size.width; window.height = window_client_rect.size.height; -#if defined(VULKAN_ENABLED) - if (context_vulkan && window_created) { - context_vulkan->window_resize(window_id, window.width, window.height); - } -#endif rect_changed = true; } +#if defined(VULKAN_ENABLED) + if (context_vulkan && window_created) { + // Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed. + context_vulkan->window_resize(window_id, window.width, window.height); + } +#endif } if (!window.minimized && (!(window_pos_params->flags & SWP_NOMOVE) || window_pos_params->flags & SWP_FRAMECHANGED)) { @@ -2823,14 +3014,17 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_SYSKEYUP: case WM_KEYUP: case WM_KEYDOWN: { - if (wParam == VK_SHIFT) + if (wParam == VK_SHIFT) { shift_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); - if (wParam == VK_CONTROL) + } + if (wParam == VK_CONTROL) { control_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); + } if (wParam == VK_MENU) { alt_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); - if (lParam & (1 << 24)) + if (lParam & (1 << 24)) { gr_mem = alt_mem; + } } if (mouse_mode == MOUSE_MODE_CAPTURED) { @@ -2839,10 +3033,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST); } } - /* - if (wParam==VK_WIN) TODO wtf is this? - meta_mem=uMsg==WM_KEYDOWN; - */ [[fallthrough]]; } case WM_CHAR: { @@ -2857,10 +3047,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA ke.uMsg = uMsg; ke.window_id = window_id; - if (ke.uMsg == WM_SYSKEYDOWN) + if (ke.uMsg == WM_SYSKEYDOWN) { ke.uMsg = WM_KEYDOWN; - if (ke.uMsg == WM_SYSKEYUP) + } + if (ke.uMsg == WM_SYSKEYUP) { ke.uMsg = WM_KEYUP; + } ke.wParam = wParam; ke.lParam = lParam; @@ -2888,7 +3080,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA _drag_event(window_id, touch_pos.x, touch_pos.y, ti.dwID); } else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) { _touch_event(window_id, ti.dwFlags & TOUCHEVENTF_DOWN, touch_pos.x, touch_pos.y, ti.dwID); - }; + } } bHandled = TRUE; } else { @@ -2901,7 +3093,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (bHandled) { CloseTouchInputHandle((HTOUCHINPUT)lParam); return 0; - }; + } } break; case WM_DEVICECHANGE: { @@ -2955,8 +3147,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA default: { if (user_proc) { return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam); - }; - }; + } + } } return DefWindowProcW(hWnd, uMsg, wParam, lParam); @@ -2964,10 +3156,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DisplayServerWindows *ds_win = static_cast<DisplayServerWindows *>(DisplayServer::get_singleton()); - if (ds_win) + if (ds_win) { return ds_win->WndProc(hWnd, uMsg, wParam, lParam); - else + } else { return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } } void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam) { @@ -3034,8 +3227,9 @@ void DisplayServerWindows::_process_key_events() { k->set_ctrl_pressed(false); } - if (k->get_unicode() < 32) + if (k->get_unicode() < 32) { k->set_unicode(0); + } Input::get_singleton()->parse_input_event(k); } else { @@ -3090,8 +3284,9 @@ void DisplayServerWindows::_process_key_events() { k->set_ctrl_pressed(false); } - if (k->get_unicode() < 32) + if (k->get_unicode() < 32) { k->set_unicode(0); + } k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30)))); @@ -3334,7 +3529,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win shift_mem = false; control_mem = false; meta_mem = false; - hInstance = ((OS_Windows *)OS::get_singleton())->get_hinstance(); + hInstance = static_cast<OS_Windows *>(OS::get_singleton())->get_hinstance(); pressrc = 0; old_invalid = true; @@ -3344,6 +3539,9 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win rendering_driver = p_rendering_driver; + // Init TTS + tts = memnew(TTS_Windows); + // Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink. HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll"); if (wintab_lib) { @@ -3395,7 +3593,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win wc.cbWndExtra = 0; wc.hInstance = hInstance ? hInstance : GetModuleHandle(nullptr); wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO); - wc.hCursor = nullptr; //LoadCursor(nullptr, IDC_ARROW); + wc.hCursor = nullptr; wc.hbrBackground = nullptr; wc.lpszMenuName = nullptr; wc.lpszClassName = L"Engine"; @@ -3446,11 +3644,12 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win return; } - // gl_manager->set_use_vsync(current_videomode.use_vsync); RasterizerGLES3::make_current(); } #endif + mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId()); + Point2i window_position( (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); @@ -3476,14 +3675,17 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } #endif - //set_ime_active(false); - - if (!OS::get_singleton()->is_in_low_processor_usage_mode()) { + if (!Engine::get_singleton()->is_editor_hint() && !OS::get_singleton()->is_in_low_processor_usage_mode()) { + // Increase priority for projects that are not in low-processor mode (typically games) + // to reduce the risk of frame stuttering. + // This is not done for the editor to prevent importers or resource bakers + // from making the system unresponsive. SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); DWORD index = 0; HANDLE handle = AvSetMmThreadCharacteristics("Games", &index); - if (handle) + if (handle) { AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL); + } // This is needed to make sure that background work does not starve the main thread. // This is only setting the priority of this thread, not the whole process. @@ -3498,7 +3700,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win r_error = OK; - ((OS_Windows *)OS::get_singleton())->set_main_window(windows[MAIN_WINDOW_ID].hWnd); + static_cast<OS_Windows *>(OS::get_singleton())->set_main_window(windows[MAIN_WINDOW_ID].hWnd); Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); } @@ -3535,12 +3737,16 @@ DisplayServerWindows::~DisplayServerWindows() { cursors_cache.clear(); + if (mouse_monitor) { + UnhookWindowsHookEx(mouse_monitor); + } + if (user_proc) { SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc); - }; + } #ifdef GLES3_ENABLED - // destroy windows .. NYI? + // destroy windows .. NYI? #endif if (windows.has(MAIN_WINDOW_ID)) { @@ -3578,4 +3784,8 @@ DisplayServerWindows::~DisplayServerWindows() { gl_manager = nullptr; } #endif + if (tts) { + memdelete(tts); + } + CoUninitialize(); } |