diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 62e1a433e29..4c52d883775 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3595,6 +3595,30 @@ void DisplayServerWindows::popup_close(WindowID p_window) { } } +BitField DisplayServerWindows::_get_mods() const { + BitField mask; + static unsigned char keyboard_state[256]; + if (GetKeyboardState((PBYTE)&keyboard_state)) { + if ((keyboard_state[VK_LSHIFT] & 0x80) || (keyboard_state[VK_RSHIFT] & 0x80)) { + mask.set_flag(WinKeyModifierMask::SHIFT); + } + if ((keyboard_state[VK_LCONTROL] & 0x80) || (keyboard_state[VK_RCONTROL] & 0x80)) { + mask.set_flag(WinKeyModifierMask::CTRL); + } + if ((keyboard_state[VK_LMENU] & 0x80) || (keyboard_state[VK_RMENU] & 0x80)) { + mask.set_flag(WinKeyModifierMask::ALT); + } + if ((keyboard_state[VK_RMENU] & 0x80)) { + mask.set_flag(WinKeyModifierMask::ALT_GR); + } + if ((keyboard_state[VK_LWIN] & 0x80) || (keyboard_state[VK_RWIN] & 0x80)) { + mask.set_flag(WinKeyModifierMask::META); + } + } + + return mask; +} + LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam) { _THREAD_SAFE_METHOD_ @@ -3850,7 +3874,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (((lParam >> 16) <= 0) && !engine->is_project_manager_hint() && !engine->is_editor_hint() && !GLOBAL_GET("application/run/enable_alt_space_menu")) { return 0; } - if (!alt_mem || !(GetAsyncKeyState(VK_SPACE) & (1 << 15))) { + if (!_get_mods().has_flag(WinKeyModifierMask::ALT) || !(GetAsyncKeyState(VK_SPACE) & (1 << 15))) { return 0; } SendMessage(windows[window_id].hWnd, WM_SYSKEYUP, VK_SPACE, 0); @@ -3936,20 +3960,22 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA RAWINPUT *raw = (RAWINPUT *)lpb; + const BitField &mods = _get_mods(); if (raw->header.dwType == RIM_TYPEKEYBOARD) { if (raw->data.keyboard.VKey == VK_SHIFT) { // If multiple Shifts are held down at the same time, // Windows natively only sends a KEYUP for the last one to be released. if (raw->data.keyboard.Flags & RI_KEY_BREAK) { - if (GetAsyncKeyState(VK_SHIFT) < 0) { + if (!mods.has_flag(WinKeyModifierMask::SHIFT)) { // A Shift is released, but another Shift is still held ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE); KeyEvent ke; ke.shift = false; - ke.alt = alt_mem; - ke.control = control_mem; - ke.meta = meta_mem; + ke.altgr = mods.has_flag(WinKeyModifierMask::ALT_GR); + ke.alt = mods.has_flag(WinKeyModifierMask::ALT); + ke.control = mods.has_flag(WinKeyModifierMask::CTRL); + ke.meta = mods.has_flag(WinKeyModifierMask::META); ke.uMsg = WM_KEYUP; ke.window_id = window_id; @@ -3966,9 +3992,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mm.instantiate(); mm->set_window_id(window_id); - mm->set_ctrl_pressed(control_mem); - mm->set_shift_pressed(shift_mem); - mm->set_alt_pressed(alt_mem); + mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); mm->set_pressure((raw->data.mouse.ulButtons & RI_MOUSE_LEFT_BUTTON_DOWN) ? 1.0f : 0.0f); @@ -4063,12 +4090,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; } + const BitField &mods = _get_mods(); Ref mm; mm.instantiate(); mm->set_window_id(window_id); - mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0); - mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0); - mm->set_alt_pressed(alt_mem); + mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); mm->set_pressure(windows[window_id].last_pressure); mm->set_tilt(windows[window_id].last_tilt); @@ -4213,9 +4242,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } mm->set_pen_inverted(pen_info.penFlags & (PEN_FLAG_INVERTED | PEN_FLAG_ERASER)); - mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0); - mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0); - mm->set_alt_pressed(alt_mem); + const BitField &mods = _get_mods(); + mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); mm->set_button_mask(last_button_state); @@ -4318,12 +4349,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (receiving_window_id == INVALID_WINDOW_ID) { receiving_window_id = window_id; } + + const BitField &mods = _get_mods(); Ref mm; mm.instantiate(); mm->set_window_id(receiving_window_id); - mm->set_ctrl_pressed((wParam & MK_CONTROL) != 0); - mm->set_shift_pressed((wParam & MK_SHIFT) != 0); - mm->set_alt_pressed(alt_mem); + mm->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mm->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mm->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mm->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); if ((tablet_get_current_driver() == "wintab") && wintab_available && windows[window_id].wtctx) { // Note: WinTab sends both WT_PACKET and WM_xBUTTONDOWN/UP/MOUSEMOVE events, use mouse 1/0 pressure only when last_pressure was not updated recently. @@ -4512,10 +4546,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } - mb->set_ctrl_pressed((wParam & MK_CONTROL) != 0); - mb->set_shift_pressed((wParam & MK_SHIFT) != 0); - mb->set_alt_pressed(alt_mem); - // mb->is_alt_pressed()=(wParam&MK_MENU)!=0; + const BitField &mods = _get_mods(); + mb->set_ctrl_pressed(mods.has_flag(WinKeyModifierMask::CTRL)); + mb->set_shift_pressed(mods.has_flag(WinKeyModifierMask::SHIFT)); + mb->set_alt_pressed(mods.has_flag(WinKeyModifierMask::ALT)); + mb->set_meta_pressed(mods.has_flag(WinKeyModifierMask::META)); + if (mb->is_pressed()) { last_button_state.set_flag(mouse_button_to_mask(mb->get_button_index())); } else { @@ -4691,19 +4727,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_KEYUP: case WM_SYSKEYDOWN: case WM_KEYDOWN: { - if (wParam == VK_SHIFT) { - shift_mem = (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN); - } - 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)) { - gr_mem = alt_mem; - } - } - if (windows[window_id].ime_suppress_next_keyup && (uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP)) { windows[window_id].ime_suppress_next_keyup = false; break; @@ -4714,7 +4737,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (mouse_mode == MOUSE_MODE_CAPTURED) { // When SetCapture is used, ALT+F4 hotkey is ignored by Windows, so handle it ourselves - if (wParam == VK_F4 && alt_mem && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)) { + if (wParam == VK_F4 && _get_mods().has_flag(WinKeyModifierMask::ALT) && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)) { _send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST); } } @@ -4722,13 +4745,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } case WM_CHAR: { ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE); + const BitField &mods = _get_mods(); - // Make sure we don't include modifiers for the modifier key itself. KeyEvent ke; - ke.shift = (wParam != VK_SHIFT) ? shift_mem : false; - ke.alt = (!(wParam == VK_MENU && (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN))) ? alt_mem : false; - ke.control = (wParam != VK_CONTROL) ? control_mem : false; - ke.meta = meta_mem; + ke.shift = mods.has_flag(WinKeyModifierMask::SHIFT); + ke.alt = mods.has_flag(WinKeyModifierMask::ALT); + ke.altgr = mods.has_flag(WinKeyModifierMask::ALT_GR); + ke.control = mods.has_flag(WinKeyModifierMask::CTRL); + ke.meta = mods.has_flag(WinKeyModifierMask::META); ke.uMsg = uMsg; ke.window_id = window_id; @@ -4899,10 +4923,6 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id) { WindowData &wd = windows[p_window_id]; if (wd.activate_state == WA_ACTIVE || wd.activate_state == WA_CLICKACTIVE) { last_focused_window = p_window_id; - alt_mem = false; - control_mem = false; - shift_mem = false; - gr_mem = false; _set_mouse_mode_impl(mouse_mode); if (!IsIconic(wd.hWnd)) { SetFocus(wd.hWnd); @@ -4914,7 +4934,6 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id) { track_mouse_leave_event(wd.hWnd); // Release capture unconditionally because it can be set due to dragging, in addition to captured mode. ReleaseCapture(); - alt_mem = false; wd.window_focused = false; _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT); } @@ -4985,7 +5004,7 @@ void DisplayServerWindows::_process_key_events() { k->set_physical_keycode(physical_keycode); k->set_key_label(key_label); k->set_unicode(fix_unicode(unicode)); - if (k->get_unicode() && gr_mem) { + if (k->get_unicode() && ke.altgr) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } @@ -5061,7 +5080,7 @@ void DisplayServerWindows::_process_key_events() { } k->set_unicode(fix_unicode(unicode)); } - if (k->get_unicode() && gr_mem) { + if (k->get_unicode() && ke.altgr) { k->set_alt_pressed(false); k->set_ctrl_pressed(false); } @@ -5527,11 +5546,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win drop_events = false; key_event_pos = 0; - alt_mem = false; - gr_mem = false; - shift_mem = false; - control_mem = false; - meta_mem = false; hInstance = static_cast(OS::get_singleton())->get_hinstance(); pressrc = 0; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 9a4eeba4864..7ef64d2ce3b 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -337,7 +337,7 @@ class DisplayServerWindows : public DisplayServer { struct KeyEvent { WindowID window_id; - bool alt, shift, control, meta; + bool alt, shift, control, meta, altgr; UINT uMsg; WPARAM wParam; LPARAM lParam; @@ -478,11 +478,6 @@ class DisplayServerWindows : public DisplayServer { MouseMode mouse_mode; int restore_mouse_trails = 0; - bool alt_mem = false; - bool gr_mem = false; - bool shift_mem = false; - bool control_mem = false; - bool meta_mem = false; BitField last_button_state; bool use_raw_input = false; bool drop_events = false; @@ -519,6 +514,15 @@ class DisplayServerWindows : public DisplayServer { LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); Point2i _get_screens_origin() const; + enum class WinKeyModifierMask { + ALT_GR = (1 << 1), + SHIFT = (1 << 2), + ALT = (1 << 3), + META = (1 << 4), + CTRL = (1 << 5), + }; + BitField _get_mods() const; + Error _file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector &p_filters, const TypedArray &p_options, const Callable &p_callback, bool p_options_in_cb); public: