Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Windows] Use current keyboard state instead of saved values for modifier keys. #92415

Merged
merged 1 commit into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 66 additions & 52 deletions platform/windows/display_server_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3613,6 +3613,30 @@ void DisplayServerWindows::popup_close(WindowID p_window) {
}
}

BitField<DisplayServerWindows::WinKeyModifierMask> DisplayServerWindows::_get_mods() const {
BitField<WinKeyModifierMask> 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_

Expand Down Expand Up @@ -3863,7 +3887,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);
Expand Down Expand Up @@ -3946,20 +3970,22 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA

RAWINPUT *raw = (RAWINPUT *)lpb;

const BitField<WinKeyModifierMask> &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;

Expand All @@ -3976,9 +4002,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);

Expand Down Expand Up @@ -4073,12 +4100,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
break;
}

const BitField<WinKeyModifierMask> &mods = _get_mods();
Ref<InputEventMouseMotion> 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);
Expand Down Expand Up @@ -4223,9 +4252,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<WinKeyModifierMask> &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);

Expand Down Expand Up @@ -4328,12 +4359,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<WinKeyModifierMask> &mods = _get_mods();
Ref<InputEventMouseMotion> 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.
Expand Down Expand Up @@ -4522,10 +4556,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<WinKeyModifierMask> &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 {
Expand Down Expand Up @@ -4693,19 +4729,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;
Expand All @@ -4716,21 +4739,22 @@ 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);
}
}
[[fallthrough]];
}
case WM_CHAR: {
ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
const BitField<WinKeyModifierMask> &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;

Expand Down Expand Up @@ -4894,10 +4918,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);
Expand All @@ -4909,7 +4929,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);
}
Expand Down Expand Up @@ -4980,7 +4999,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);
}
Expand Down Expand Up @@ -5056,7 +5075,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);
}
Expand Down Expand Up @@ -5522,11 +5541,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_Windows *>(OS::get_singleton())->get_hinstance();

pressrc = 0;
Expand Down
16 changes: 10 additions & 6 deletions platform/windows/display_server_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<MouseButtonMask> last_button_state;
bool use_raw_input = false;
bool drop_events = false;
Expand Down Expand Up @@ -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<WinKeyModifierMask> _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<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb);

public:
Expand Down
Loading