diff options
Diffstat (limited to 'platform/windows/display_server_windows.cpp')
-rw-r--r-- | platform/windows/display_server_windows.cpp | 229 |
1 files changed, 194 insertions, 35 deletions
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 2d787c84e2..89a7114583 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -735,9 +735,23 @@ 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_MOUSE_PASSTHROUGH_BIT) { + wd.mpass = true; + } if (p_flags & WINDOW_FLAG_POPUP_BIT) { wd.is_popup = true; } + if (p_flags & WINDOW_FLAG_TRANSPARENT_BIT) { + DWM_BLURBEHIND bb; + ZeroMemory(&bb, sizeof(bb)); + HRGN hRgn = CreateRectRgn(0, 0, -1, -1); + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = hRgn; + bb.fEnable = TRUE; + DwmEnableBlurBehindWindow(wd.hWnd, &bb); + + wd.layered_window = 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); @@ -775,6 +789,9 @@ void DisplayServerWindows::show_window(WindowID p_id) { SetForegroundWindow(wd.hWnd); // Slightly higher priority. SetFocus(wd.hWnd); // Set keyboard focus. } + if (wd.always_on_top) { + SetWindowPos(wd.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0)); + } } void DisplayServerWindows::delete_sub_window(WindowID p_window) { @@ -918,7 +935,7 @@ void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); - if (windows[p_window].mpath.size() == 0) { + if (windows[p_window].mpass || windows[p_window].mpath.size() == 0) { SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE); } else { POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size()); @@ -1499,6 +1516,10 @@ 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_MOUSE_PASSTHROUGH: { + wd.mpass = p_enabled; + _update_window_mouse_passthrough(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."); @@ -1530,6 +1551,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_MOUSE_PASSTHROUGH: { + return wd.mpass; + } break; case WINDOW_FLAG_POPUP: { return wd.is_popup; } break; @@ -1586,6 +1610,58 @@ bool DisplayServerWindows::can_any_window_draw() const { return false; } +Vector2i DisplayServerWindows::ime_get_selection() const { + _THREAD_SAFE_METHOD_ + + DisplayServer::WindowID window_id = _get_focused_window_or_popup(); + const WindowData &wd = windows[window_id]; + if (!wd.ime_active) { + return Vector2i(); + } + + int cursor = ImmGetCompositionStringW(wd.im_himc, GCS_CURSORPOS, nullptr, 0); + + int32_t length = ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, nullptr, 0); + wchar_t *string = reinterpret_cast<wchar_t *>(memalloc(length)); + ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, string, length); + + int32_t utf32_cursor = 0; + for (int32_t i = 0; i < length / sizeof(wchar_t); i++) { + if ((string[i] & 0xfffffc00) == 0xd800) { + i++; + } + if (i < cursor) { + utf32_cursor++; + } else { + break; + } + } + + memdelete(string); + + return Vector2i(utf32_cursor, 0); +} + +String DisplayServerWindows::ime_get_text() const { + _THREAD_SAFE_METHOD_ + + DisplayServer::WindowID window_id = _get_focused_window_or_popup(); + const WindowData &wd = windows[window_id]; + if (!wd.ime_active) { + return String(); + } + + String ret; + int32_t length = ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, nullptr, 0); + wchar_t *string = reinterpret_cast<wchar_t *>(memalloc(length)); + ImmGetCompositionStringW(wd.im_himc, GCS_COMPSTR, string, length); + ret.parse_utf16((char16_t *)string, length / sizeof(wchar_t)); + + memdelete(string); + + return ret; +} + void DisplayServerWindows::window_set_ime_active(const bool p_active, WindowID p_window) { _THREAD_SAFE_METHOD_ @@ -1593,11 +1669,14 @@ void DisplayServerWindows::window_set_ime_active(const bool p_active, WindowID p WindowData &wd = windows[p_window]; if (p_active) { + wd.ime_active = true; ImmAssociateContext(wd.hWnd, wd.im_himc); - + CreateCaret(wd.hWnd, NULL, 1, 1); window_set_ime_position(wd.im_position, p_window); } else { ImmAssociateContext(wd.hWnd, (HIMC)0); + DestroyCaret(); + wd.ime_active = false; } } @@ -1615,7 +1694,7 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI } COMPOSITIONFORM cps; - cps.dwStyle = CFS_FORCE_POSITION; + cps.dwStyle = CFS_POINT; cps.ptCurrentPos.x = wd.im_position.x; cps.ptCurrentPos.y = wd.im_position.y; ImmSetCompositionWindow(himc, &cps); @@ -2464,6 +2543,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // Process window messages. switch (uMsg) { + case WM_NCHITTEST: { + if (windows[window_id].mpass) { + return HTTRANSPARENT; + } + } break; case WM_MOUSEACTIVATE: { if (windows[window_id].no_focus) { return MA_NOACTIVATEANDEAT; // Do not activate, and discard mouse messages. @@ -3324,10 +3408,18 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA windows[window_id].focus_timer_id = 0U; } } break; - case WM_SYSKEYDOWN: case WM_SYSKEYUP: case WM_KEYUP: + if (windows[window_id].ime_suppress_next_keyup) { + windows[window_id].ime_suppress_next_keyup = false; + break; + } + [[fallthrough]]; + case WM_SYSKEYDOWN: case WM_KEYDOWN: { + if (windows[window_id].ime_in_progress) { + break; + } if (wParam == VK_SHIFT) { shift_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); } @@ -3373,9 +3465,49 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA key_event_buffer[key_event_pos++] = ke; } break; + case WM_IME_COMPOSITION: { + CANDIDATEFORM cf; + cf.dwIndex = 0; + + cf.dwStyle = CFS_CANDIDATEPOS; + cf.ptCurrentPos.x = windows[window_id].im_position.x; + cf.ptCurrentPos.y = windows[window_id].im_position.y; + ImmSetCandidateWindow(windows[window_id].im_himc, &cf); + + cf.dwStyle = CFS_EXCLUDE; + cf.rcArea.left = windows[window_id].im_position.x; + cf.rcArea.right = windows[window_id].im_position.x; + cf.rcArea.top = windows[window_id].im_position.y; + cf.rcArea.bottom = windows[window_id].im_position.y; + ImmSetCandidateWindow(windows[window_id].im_himc, &cf); + + if (windows[window_id].ime_active) { + SetCaretPos(windows[window_id].im_position.x, windows[window_id].im_position.y); + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_OS_IME_UPDATE); + } + } break; case WM_INPUTLANGCHANGEREQUEST: { // FIXME: Do something? } break; + case WM_IME_STARTCOMPOSITION: { + if (windows[window_id].ime_active) { + windows[window_id].ime_in_progress = true; + if (key_event_pos > 0) { + key_event_pos--; + } + } + return 0; + } break; + case WM_IME_ENDCOMPOSITION: { + if (windows[window_id].ime_active) { + windows[window_id].ime_in_progress = false; + windows[window_id].ime_suppress_next_keyup = true; + } + return 0; + } break; + case WM_IME_NOTIFY: { + return 0; + } break; case WM_TOUCH: { BOOL bHandled = FALSE; UINT cInputs = LOWORD(wParam); @@ -3484,6 +3616,7 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM alt_mem = false; control_mem = false; shift_mem = false; + gr_mem = false; // Restore mouse mode. _set_mouse_mode_impl(mouse_mode); @@ -3527,24 +3660,36 @@ void DisplayServerWindows::_process_key_events() { Ref<InputEventKey> k; k.instantiate(); + Key keycode = KeyMappingWindows::get_keysym(MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK)); + Key key_label = keycode; + Key physical_keycode = KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)); + + static BYTE keyboard_state[256]; + memset(keyboard_state, 0, 256); + wchar_t chars[256] = {}; + UINT extended_code = MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX); + if (!(ke.lParam & (1 << 24)) && ToUnicodeEx(extended_code, (ke.lParam >> 16) & 0xFF, keyboard_state, chars, 255, 4, GetKeyboardLayout(0)) > 0) { + String keysym = String::utf16((char16_t *)chars, 255); + if (!keysym.is_empty()) { + key_label = fix_key_label(keysym[0], keycode); + } + } + k->set_window_id(ke.window_id); k->set_shift_pressed(ke.shift); k->set_alt_pressed(ke.alt); k->set_ctrl_pressed(ke.control); k->set_meta_pressed(ke.meta); k->set_pressed(true); - k->set_keycode((Key)KeyMappingWindows::get_keysym(MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK))); - k->set_physical_keycode((Key)(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)))); - k->set_unicode(unicode); + k->set_keycode(keycode); + k->set_physical_keycode(physical_keycode); + k->set_key_label(key_label); + k->set_unicode(fix_unicode(unicode)); if (k->get_unicode() && gr_mem) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } - if (k->get_unicode() < 32) { - k->set_unicode(0); - } - Input::get_singleton()->parse_input_event(k); } else { // Do nothing. @@ -3563,14 +3708,28 @@ void DisplayServerWindows::_process_key_events() { k->set_pressed(ke.uMsg == WM_KEYDOWN); + Key keycode = KeyMappingWindows::get_keysym(ke.wParam); if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) { // Special case for Numpad Enter key. - k->set_keycode(Key::KP_ENTER); - } else { - k->set_keycode((Key)KeyMappingWindows::get_keysym(ke.wParam)); + keycode = Key::KP_ENTER; + } + Key key_label = keycode; + Key physical_keycode = KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)); + + static BYTE keyboard_state[256]; + memset(keyboard_state, 0, 256); + wchar_t chars[256] = {}; + UINT extended_code = MapVirtualKey((ke.lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX); + if (!(ke.lParam & (1 << 24)) && ToUnicodeEx(extended_code, (ke.lParam >> 16) & 0xFF, keyboard_state, chars, 255, 4, GetKeyboardLayout(0)) > 0) { + String keysym = String::utf16((char16_t *)chars, 255); + if (!keysym.is_empty()) { + key_label = fix_key_label(keysym[0], keycode); + } } - k->set_physical_keycode((Key)(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)))); + k->set_keycode(keycode); + k->set_physical_keycode(physical_keycode); + k->set_key_label(key_label); if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) { char32_t unicode = key_event_buffer[i + 1].wParam; @@ -3591,17 +3750,13 @@ void DisplayServerWindows::_process_key_events() { } else { prev_wck = 0; } - k->set_unicode(unicode); + k->set_unicode(fix_unicode(unicode)); } if (k->get_unicode() && gr_mem) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } - if (k->get_unicode() < 32) { - k->set_unicode(0); - } - k->set_echo((ke.uMsg == WM_KEYDOWN && (ke.lParam & (1 << 30)))); Input::get_singleton()->parse_input_event(k); @@ -3656,7 +3811,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, DWORD dwExStyle; DWORD dwStyle; - _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); + _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle); RECT WindowRect; @@ -3812,7 +3967,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, // IME. wd.im_himc = ImmGetContext(wd.hWnd); - ImmReleaseContext(wd.hWnd, wd.im_himc); + ImmAssociateContext(wd.hWnd, (HIMC)0); wd.im_position = Vector2(); @@ -3906,6 +4061,8 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) { } DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) { + KeyMappingWindows::initialize(); + drop_events = false; key_event_pos = 0; @@ -4013,7 +4170,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win wc.lpszClassName = L"Engine"; if (!RegisterClassExW(&wc)) { - MessageBox(nullptr, "Failed To Register The Window Class.", "ERROR", MB_OK | MB_ICONEXCLAMATION); + MessageBoxW(nullptr, L"Failed To Register The Window Class.", L"ERROR", MB_OK | MB_ICONEXCLAMATION); r_error = ERR_UNAVAILABLE; return; } @@ -4092,7 +4249,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win // from making the system unresponsive. SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); DWORD index = 0; - HANDLE handle = AvSetMmThreadCharacteristics("Games", &index); + HANDLE handle = AvSetMmThreadCharacteristicsW(L"Games", &index); if (handle) { AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL); } @@ -4130,18 +4287,20 @@ DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_drive if (r_error != OK) { if (p_rendering_driver == "vulkan") { String executable_name = OS::get_singleton()->get_executable_path().get_file(); - OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n" - "Please try updating your GPU driver or try using the OpenGL 3 driver.\n" - "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n'./" + - executable_name + " --rendering-driver opengl3'.\n " - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" + "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" + "You can enable the OpenGL 3 driver by starting the engine from the\n" + "command line with the command:\n'%s --rendering-driver opengl3'\n\n" + "If you have recently updated your video card drivers, try rebooting.", + executable_name), + "Unable to initialize Vulkan video driver"); } else { - OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n" - "Please try updating your GPU driver.\n" - "If you have updated your graphics drivers recently, try rebooting.", - "Unable to initialize Video driver"); + OS::get_singleton()->alert( + "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n" + "If possible, consider updating your video card drivers.\n\n" + "If you have recently updated your video card drivers, try rebooting.", + "Unable to initialize OpenGL video driver"); } } return ds; |