summaryrefslogtreecommitdiff
path: root/platform/windows
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows')
-rw-r--r--platform/windows/README.md2
-rw-r--r--platform/windows/display_server_windows.cpp258
-rw-r--r--platform/windows/display_server_windows.h13
-rw-r--r--platform/windows/export/export.cpp1
-rw-r--r--platform/windows/export/export_plugin.cpp316
-rw-r--r--platform/windows/export/export_plugin.h36
-rw-r--r--platform/windows/gl_manager_windows.h1
-rw-r--r--platform/windows/joypad_windows.cpp29
-rw-r--r--platform/windows/key_mapping_windows.cpp788
-rw-r--r--platform/windows/key_mapping_windows.h2
-rw-r--r--platform/windows/logo.pngbin1536 -> 0 bytes
-rw-r--r--platform/windows/logo.svg1
-rw-r--r--platform/windows/os_windows.cpp55
-rw-r--r--platform/windows/os_windows.h5
-rw-r--r--platform/windows/run_icon.svg1
15 files changed, 981 insertions, 527 deletions
diff --git a/platform/windows/README.md b/platform/windows/README.md
index c04032ae1d..4c775576fe 100644
--- a/platform/windows/README.md
+++ b/platform/windows/README.md
@@ -7,7 +7,7 @@ used by this platform.
## Documentation
-- [Compiling for Windows](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_windows.html)
+- [Compiling for Windows](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html)
- Instructions on building this platform port from source.
- [Exporting for Windows](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_windows.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index ba0f494723..cc230575c8 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -257,7 +257,7 @@ Point2i DisplayServerWindows::mouse_get_position() const {
return Point2i(p.x, p.y) - _get_screens_origin();
}
-MouseButton DisplayServerWindows::mouse_get_button_state() const {
+BitField<MouseButtonMask> DisplayServerWindows::mouse_get_button_state() const {
return last_button_state;
}
@@ -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());
@@ -1463,6 +1480,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.");
@@ -1494,6 +1515,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;
@@ -1550,6 +1574,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 / int32_t(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_
@@ -1557,11 +1633,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;
}
}
@@ -1579,7 +1658,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);
@@ -2428,6 +2507,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.
@@ -2507,6 +2591,25 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
return 0;
}
} break;
+ case WM_ERASEBKGND: {
+ Color early_color;
+ if (!_get_window_early_clear_override(early_color)) {
+ break;
+ }
+ bool must_recreate_brush = !window_bkg_brush || window_bkg_brush_color != early_color.to_argb32();
+ if (must_recreate_brush) {
+ if (window_bkg_brush) {
+ DeleteObject(window_bkg_brush);
+ }
+ window_bkg_brush = CreateSolidBrush(RGB(early_color.get_r8(), early_color.get_g8(), early_color.get_b8()));
+ }
+ HDC hdc = (HDC)wParam;
+ RECT rect = {};
+ if (GetUpdateRect(hWnd, &rect, true)) {
+ FillRect(hdc, &rect, window_bkg_brush);
+ }
+ return 1;
+ } break;
case WM_PAINT: {
Main::force_redraw();
} break;
@@ -3126,9 +3229,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mb->set_alt_pressed(alt_mem);
// mb->is_alt_pressed()=(wParam&MK_MENU)!=0;
if (mb->is_pressed()) {
- last_button_state |= mouse_button_to_mask(mb->get_button_index());
+ last_button_state.set_flag(mouse_button_to_mask(mb->get_button_index()));
} else {
- last_button_state &= ~mouse_button_to_mask(mb->get_button_index());
+ last_button_state.clear_flag(mouse_button_to_mask(mb->get_button_index()));
}
mb->set_button_mask(last_button_state);
@@ -3169,7 +3272,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Send release for mouse wheel.
Ref<InputEventMouseButton> mbd = mb->duplicate();
mbd->set_window_id(window_id);
- last_button_state &= ~mouse_button_to_mask(mbd->get_button_index());
+ last_button_state.clear_flag(mouse_button_to_mask(mbd->get_button_index()));
mbd->set_button_mask(last_button_state);
mbd->set_pressed(false);
Input::get_singleton()->parse_input_event(mbd);
@@ -3278,10 +3381,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);
}
@@ -3327,9 +3438,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);
@@ -3438,6 +3589,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);
@@ -3481,24 +3633,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.
@@ -3517,14 +3681,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;
@@ -3545,17 +3723,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);
@@ -3610,7 +3784,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;
@@ -3766,7 +3940,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();
@@ -3860,6 +4034,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;
@@ -3955,7 +4131,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
memset(&wc, 0, sizeof(WNDCLASSEXW));
wc.cbSize = sizeof(WNDCLASSEXW);
- wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS;
+ wc.style = CS_OWNDC | CS_DBLCLKS;
wc.lpfnWndProc = (WNDPROC)::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
@@ -3967,7 +4143,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;
}
@@ -4046,7 +4222,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);
}
@@ -4084,18 +4260,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;
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index feed9f35ed..0d2137d048 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -370,6 +370,7 @@ class DisplayServerWindows : public DisplayServer {
bool window_has_focus = false;
bool exclusive = false;
bool context_created = false;
+ bool mpass = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;
@@ -404,6 +405,9 @@ class DisplayServerWindows : public DisplayServer {
// IME
HIMC im_himc;
Vector2 im_position;
+ bool ime_active = false;
+ bool ime_in_progress = false;
+ bool ime_suppress_next_keyup = false;
bool layered_window = false;
@@ -446,12 +450,14 @@ class DisplayServerWindows : public DisplayServer {
bool shift_mem = false;
bool control_mem = false;
bool meta_mem = false;
- MouseButton last_button_state = MouseButton::NONE;
+ BitField<MouseButtonMask> last_button_state;
bool use_raw_input = false;
bool drop_events = false;
bool in_dispatch_input_event = false;
WNDCLASSEXW wc;
+ HBRUSH window_bkg_brush = nullptr;
+ uint32_t window_bkg_brush_color = 0;
HCURSOR cursors[CURSOR_MAX] = { nullptr };
CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
@@ -506,7 +512,7 @@ public:
virtual void warp_mouse(const Point2i &p_position) override;
virtual Point2i mouse_get_position() const override;
- virtual MouseButton mouse_get_button_state() const override;
+ virtual BitField<MouseButtonMask> mouse_get_button_state() const override;
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
@@ -589,6 +595,9 @@ public:
virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual Point2i ime_get_selection() const override;
+ virtual String ime_get_text() const override;
+
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index b0e2f5a05b..4112bb84b5 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -51,7 +51,6 @@ void register_windows_exporter() {
Ref<EditorExportPlatformWindows> platform;
platform.instantiate();
- platform->set_logo(ImageTexture::create_from_image(memnew(Image(_windows_logo))));
platform->set_name("Windows Desktop");
platform->set_os_name("Windows");
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 7c61a79fc8..4107a8a17e 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -34,6 +34,14 @@
#include "core/io/image_loader.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
+#include "editor/editor_scale.h"
+#include "platform/windows/logo_svg.gen.h"
+#include "platform/windows/run_icon_svg.gen.h"
+
+#include "modules/modules_enabled.gen.h" // For svg.
+#ifdef MODULE_SVG_ENABLED
+#include "modules/svg/image_loader_svg.h"
+#endif
Error EditorExportPlatformWindows::_process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path) {
static const uint8_t icon_size[] = { 16, 32, 48, 64, 128, 0 /*256*/ };
@@ -168,9 +176,39 @@ Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset>
}
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- String pck_path = p_path;
- if (p_preset->get("binary_format/embed_pck")) {
- pck_path = p_path.get_basename() + ".tmp";
+ bool export_as_zip = p_path.ends_with("zip");
+ bool embedded = p_preset->get("binary_format/embed_pck");
+
+ String pkg_name;
+ if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
+ pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ } else {
+ pkg_name = "Unnamed";
+ }
+
+ pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
+
+ // Setup temp folder.
+ String path = p_path;
+ String tmp_dir_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name);
+ Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path);
+ if (export_as_zip) {
+ if (tmp_app_dir.is_null()) {
+ return ERR_CANT_CREATE;
+ }
+ if (DirAccess::exists(tmp_dir_path)) {
+ if (tmp_app_dir->change_dir(tmp_dir_path) == OK) {
+ tmp_app_dir->erase_contents_recursive();
+ }
+ }
+ tmp_app_dir->make_dir_recursive(tmp_dir_path);
+ path = tmp_dir_path.path_join(p_path.get_file().get_basename() + ".exe");
+ }
+
+ // Export project.
+ String pck_path = path;
+ if (embedded) {
+ pck_path = pck_path.get_basename() + ".tmp";
}
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
if (p_preset->get("codesign/enable") && err == OK) {
@@ -181,7 +219,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
}
- if (p_preset->get("binary_format/embed_pck") && err == OK) {
+ if (embedded && err == OK) {
Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
err = tmp_dir->rename(pck_path, p_path);
if (err != OK) {
@@ -189,6 +227,27 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
}
}
+ // ZIP project.
+ if (export_as_zip) {
+ if (FileAccess::exists(p_path)) {
+ OS::get_singleton()->move_to_trash(p_path);
+ }
+
+ Ref<FileAccess> io_fa_dst;
+ zlib_filefunc_def io_dst = zipio_create_io(&io_fa_dst);
+ zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
+
+ zip_folder_recursive(zip, tmp_dir_path, "", pkg_name);
+
+ zipClose(zip, nullptr);
+
+ if (tmp_app_dir->change_dir(tmp_dir_path) == OK) {
+ tmp_app_dir->erase_contents_recursive();
+ tmp_app_dir->change_dir("..");
+ tmp_app_dir->remove(pkg_name);
+ }
+ }
+
return err;
}
@@ -199,6 +258,7 @@ String EditorExportPlatformWindows::get_template_file_name(const String &p_targe
List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
List<String> list;
list.push_back("exe");
+ list.push_back("zip");
return list;
}
@@ -212,6 +272,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
+
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
@@ -235,6 +296,29 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
+
+ String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n"
+ "$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n"
+ "$trigger = New-ScheduledTaskTrigger -Once -At 00:00\n"
+ "$settings = New-ScheduledTaskSettingsSet\n"
+ "$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings\n"
+ "Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true\n"
+ "Start-ScheduledTask -TaskName godot_remote_debug\n"
+ "while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }\n"
+ "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue";
+
+ String cleanup_script = "Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue\n"
+ "Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue\n"
+ "Remove-Item -Recurse -Force '{temp_dir}'";
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22"));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_ssh", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/extra_args_scp", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/run_script", PROPERTY_HINT_MULTILINE_TEXT), run_script));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/cleanup_script", PROPERTY_HINT_MULTILINE_TEXT), cleanup_script));
}
Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon) {
@@ -659,3 +743,227 @@ Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int6
}
return OK;
}
+
+Ref<Texture2D> EditorExportPlatformWindows::get_run_icon() const {
+ return run_icon;
+}
+
+bool EditorExportPlatformWindows::poll_export() {
+ Ref<EditorExportPreset> preset;
+
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
+ Ref<EditorExportPreset> ep = EditorExport::get_singleton()->get_export_preset(i);
+ if (ep->is_runnable() && ep->get_platform() == this) {
+ preset = ep;
+ break;
+ }
+ }
+
+ int prev = menu_options;
+ menu_options = (preset.is_valid() && preset->get("ssh_remote_deploy/enabled").operator bool());
+ if (ssh_pid != 0 || !cleanup_commands.is_empty()) {
+ if (menu_options == 0) {
+ cleanup();
+ } else {
+ menu_options += 1;
+ }
+ }
+ return menu_options != prev;
+}
+
+Ref<ImageTexture> EditorExportPlatformWindows::get_option_icon(int p_index) const {
+ return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
+}
+
+int EditorExportPlatformWindows::get_options_count() const {
+ return menu_options;
+}
+
+String EditorExportPlatformWindows::get_option_label(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall") : TTR("Run on remote Windows system");
+}
+
+String EditorExportPlatformWindows::get_option_tooltip(int p_index) const {
+ return (p_index) ? TTR("Stop and uninstall running project from the remote system") : TTR("Run exported project on remote Windows system");
+}
+
+void EditorExportPlatformWindows::cleanup() {
+ if (ssh_pid != 0 && OS::get_singleton()->is_process_running(ssh_pid)) {
+ print_line("Terminating connection...");
+ OS::get_singleton()->kill(ssh_pid);
+ OS::get_singleton()->delay_usec(1000);
+ }
+
+ if (!cleanup_commands.is_empty()) {
+ print_line("Stopping and deleting previous version...");
+ for (const SSHCleanupCommand &cmd : cleanup_commands) {
+ if (cmd.wait) {
+ ssh_run_on_remote(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ } else {
+ ssh_run_on_remote_no_wait(cmd.host, cmd.port, cmd.ssh_args, cmd.cmd_args);
+ }
+ }
+ }
+ ssh_pid = 0;
+ cleanup_commands.clear();
+}
+
+Error EditorExportPlatformWindows::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
+ cleanup();
+ if (p_device) { // Stop command, cleanup only.
+ return OK;
+ }
+
+ EditorProgress ep("run", TTR("Running..."), 5);
+
+ const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("windows");
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (!da->dir_exists(dest)) {
+ Error err = da->make_dir_recursive(dest);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(TTR("Could not create temp directory:") + "\n" + dest);
+ return err;
+ }
+ }
+
+ String host = p_preset->get("ssh_remote_deploy/host").operator String();
+ String port = p_preset->get("ssh_remote_deploy/port").operator String();
+ if (port.is_empty()) {
+ port = "22";
+ }
+ Vector<String> extra_args_ssh = p_preset->get("ssh_remote_deploy/extra_args_ssh").operator String().split(" ", false);
+ Vector<String> extra_args_scp = p_preset->get("ssh_remote_deploy/extra_args_scp").operator String().split(" ", false);
+
+ const String basepath = dest.path_join("tmp_windows_export");
+
+#define CLEANUP_AND_RETURN(m_err) \
+ { \
+ if (da->file_exists(basepath + ".zip")) { \
+ da->remove(basepath + ".zip"); \
+ } \
+ if (da->file_exists(basepath + "_start.ps1")) { \
+ da->remove(basepath + "_start.ps1"); \
+ } \
+ if (da->file_exists(basepath + "_clean.ps1")) { \
+ da->remove(basepath + "_clean.ps1"); \
+ } \
+ return m_err; \
+ } \
+ ((void)0)
+
+ if (ep.step(TTR("Exporting project..."), 1)) {
+ return ERR_SKIP;
+ }
+ Error err = export_project(p_preset, true, basepath + ".zip", p_debug_flags);
+ if (err != OK) {
+ DirAccess::remove_file_or_error(basepath + ".zip");
+ return err;
+ }
+
+ String cmd_args;
+ {
+ Vector<String> cmd_args_list;
+ gen_debug_flags(cmd_args_list, p_debug_flags);
+ for (int i = 0; i < cmd_args_list.size(); i++) {
+ if (i != 0) {
+ cmd_args += " ";
+ }
+ cmd_args += cmd_args_list[i];
+ }
+ }
+
+ const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT);
+ int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port");
+
+ print_line("Creating temporary directory...");
+ ep.step(TTR("Creating temporary directory..."), 2);
+ String temp_dir;
+ err = ssh_run_on_remote(host, port, extra_args_ssh, "powershell -command \\\"\\$tmp = Join-Path \\$Env:Temp \\$(New-Guid); New-Item -Type Directory -Path \\$tmp | Out-Null; Write-Output \\$tmp\\\"", &temp_dir);
+ if (err != OK || temp_dir.is_empty()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Uploading archive...");
+ ep.step(TTR("Uploading archive..."), 3);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + ".zip", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ {
+ String run_script = p_preset->get("ssh_remote_deploy/run_script");
+ run_script = run_script.replace("{temp_dir}", temp_dir);
+ run_script = run_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ run_script = run_script.replace("{exe_name}", basepath.get_file() + ".exe");
+ run_script = run_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_start.ps1", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(run_script);
+ }
+
+ {
+ String clean_script = p_preset->get("ssh_remote_deploy/cleanup_script");
+ clean_script = clean_script.replace("{temp_dir}", temp_dir);
+ clean_script = clean_script.replace("{archive_name}", basepath.get_file() + ".zip");
+ clean_script = clean_script.replace("{exe_name}", basepath.get_file() + ".exe");
+ clean_script = clean_script.replace("{cmd_args}", cmd_args);
+
+ Ref<FileAccess> f = FileAccess::open(basepath + "_clean.ps1", FileAccess::WRITE);
+ if (f.is_null()) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ f->store_string(clean_script);
+ }
+
+ print_line("Uploading scripts...");
+ ep.step(TTR("Uploading scripts..."), 4);
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_start.ps1", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+ err = ssh_push_to_remote(host, port, extra_args_scp, basepath + "_clean.ps1", temp_dir);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ print_line("Starting project...");
+ ep.step(TTR("Starting project..."), 5);
+ err = ssh_run_on_remote_no_wait(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_start.ps1"), &ssh_pid, (use_remote) ? dbg_port : -1);
+ if (err != OK) {
+ CLEANUP_AND_RETURN(err);
+ }
+
+ cleanup_commands.clear();
+ cleanup_commands.push_back(SSHCleanupCommand(host, port, extra_args_ssh, vformat("powershell -file \"%s\\%s\"", temp_dir, basepath.get_file() + "_clean.ps1")));
+
+ print_line("Project started.");
+
+ CLEANUP_AND_RETURN(OK);
+#undef CLEANUP_AND_RETURN
+}
+
+EditorExportPlatformWindows::EditorExportPlatformWindows() {
+#ifdef MODULE_SVG_ENABLED
+ Ref<Image> img = memnew(Image);
+ const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE);
+
+ ImageLoaderSVG img_loader;
+ img_loader.create_image_from_string(img, _windows_logo_svg, EDSCALE, upsample, false);
+ set_logo(ImageTexture::create_from_image(img));
+
+ img_loader.create_image_from_string(img, _windows_run_icon_svg, EDSCALE, upsample, false);
+ run_icon = ImageTexture::create_from_image(img);
+#endif
+
+ Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
+ if (theme.is_valid()) {
+ stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ } else {
+ stop_icon.instantiate();
+ }
+}
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index 96608728d3..fa75a17a1f 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -35,9 +35,32 @@
#include "core/os/os.h"
#include "editor/editor_settings.h"
#include "editor/export/editor_export_platform_pc.h"
-#include "platform/windows/logo.gen.h"
class EditorExportPlatformWindows : public EditorExportPlatformPC {
+ struct SSHCleanupCommand {
+ String host;
+ String port;
+ Vector<String> ssh_args;
+ String cmd_args;
+ bool wait = false;
+
+ SSHCleanupCommand(){};
+ SSHCleanupCommand(const String &p_host, const String &p_port, const Vector<String> &p_ssh_arg, const String &p_cmd_args, bool p_wait = false) {
+ host = p_host;
+ port = p_port;
+ ssh_args = p_ssh_arg;
+ cmd_args = p_cmd_args;
+ wait = p_wait;
+ };
+ };
+
+ Ref<ImageTexture> run_icon;
+ Ref<ImageTexture> stop_icon;
+
+ Vector<SSHCleanupCommand> cleanup_commands;
+ OS::ProcessID ssh_pid = 0;
+ int menu_options = 0;
+
Error _process_icon(const Ref<EditorExportPreset> &p_preset, const String &p_src_path, const String &p_dst_path);
Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path, bool p_console_icon);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
@@ -53,6 +76,17 @@ public:
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
+
+ virtual Ref<Texture2D> get_run_icon() const override;
+ virtual bool poll_export() override;
+ virtual Ref<ImageTexture> get_option_icon(int p_index) const override;
+ virtual int get_options_count() const override;
+ virtual String get_option_label(int p_index) const override;
+ virtual String get_option_tooltip(int p_index) const override;
+ virtual Error run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) override;
+ virtual void cleanup() override;
+
+ EditorExportPlatformWindows();
};
#endif // WINDOWS_EXPORT_PLUGIN_H
diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows.h
index b97d0f667c..361c559a5a 100644
--- a/platform/windows/gl_manager_windows.h
+++ b/platform/windows/gl_manager_windows.h
@@ -74,7 +74,6 @@ private:
GLWindow *_current_window = nullptr;
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr;
- PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = nullptr;
// funcs
void _internal_set_current_window(GLWindow *p_win);
diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp
index aed5f5b8dc..7ae26e6cf4 100644
--- a/platform/windows/joypad_windows.cpp
+++ b/platform/windows/joypad_windows.cpp
@@ -101,10 +101,12 @@ bool JoypadWindows::is_xinput_device(const GUID *p_guid) {
static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x28DE, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
+ static GUID IID_XSWirelessGamepad = { MAKELONG(0x045E, 0x0B13), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
if (memcmp(p_guid, &IID_ValveStreamingGamepad, sizeof(*p_guid)) == 0 ||
memcmp(p_guid, &IID_X360WiredGamepad, sizeof(*p_guid)) == 0 ||
- memcmp(p_guid, &IID_X360WirelessGamepad, sizeof(*p_guid)) == 0)
+ memcmp(p_guid, &IID_X360WirelessGamepad, sizeof(*p_guid)) == 0 ||
+ memcmp(p_guid, &IID_XSWirelessGamepad, sizeof(*p_guid)) == 0)
return true;
PRAWINPUTDEVICELIST dev_list = nullptr;
@@ -420,38 +422,43 @@ void JoypadWindows::process_joypads() {
}
void JoypadWindows::post_hat(int p_device, DWORD p_dpad) {
- HatMask dpad_val = (HatMask)0;
+ BitField<HatMask> dpad_val;
// Should be -1 when centered, but according to docs:
// "Some drivers report the centered position of the POV indicator as 65,535. Determine whether the indicator is centered as follows:
// BOOL POVCentered = (LOWORD(dwPOV) == 0xFFFF);"
// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v%3Dvs.85)#remarks
if (LOWORD(p_dpad) == 0xFFFF) {
- dpad_val = (HatMask)HatMask::CENTER;
+ // Do nothing.
+ // dpad_val.set_flag(HatMask::CENTER);
}
if (p_dpad == 0) {
- dpad_val = (HatMask)HatMask::UP;
+ dpad_val.set_flag(HatMask::UP);
} else if (p_dpad == 4500) {
- dpad_val = (HatMask)(HatMask::UP | HatMask::RIGHT);
+ dpad_val.set_flag(HatMask::UP);
+ dpad_val.set_flag(HatMask::RIGHT);
} else if (p_dpad == 9000) {
- dpad_val = (HatMask)HatMask::RIGHT;
+ dpad_val.set_flag(HatMask::RIGHT);
} else if (p_dpad == 13500) {
- dpad_val = (HatMask)(HatMask::RIGHT | HatMask::DOWN);
+ dpad_val.set_flag(HatMask::RIGHT);
+ dpad_val.set_flag(HatMask::DOWN);
} else if (p_dpad == 18000) {
- dpad_val = (HatMask)HatMask::DOWN;
+ dpad_val.set_flag(HatMask::DOWN);
} else if (p_dpad == 22500) {
- dpad_val = (HatMask)(HatMask::DOWN | HatMask::LEFT);
+ dpad_val.set_flag(HatMask::DOWN);
+ dpad_val.set_flag(HatMask::LEFT);
} else if (p_dpad == 27000) {
- dpad_val = (HatMask)HatMask::LEFT;
+ dpad_val.set_flag(HatMask::LEFT);
} else if (p_dpad == 31500) {
- dpad_val = (HatMask)(HatMask::LEFT | HatMask::UP);
+ dpad_val.set_flag(HatMask::LEFT);
+ dpad_val.set_flag(HatMask::UP);
}
input->joy_hat(p_device, dpad_val);
}
diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp
index 86471f188f..d43f74126d 100644
--- a/platform/windows/key_mapping_windows.cpp
+++ b/platform/windows/key_mapping_windows.cpp
@@ -30,490 +30,386 @@
#include "key_mapping_windows.h"
-#include <stdio.h>
+#include "core/templates/hash_map.h"
// This provides translation from Windows virtual key codes to Godot and back.
// See WinUser.h and the below for documentation:
// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
-struct _WinTranslatePair {
- Key keysym;
- unsigned int keycode;
+struct HashMapHasherKeys {
+ static _FORCE_INLINE_ uint32_t hash(const Key p_key) { return hash_fmix32(static_cast<uint32_t>(p_key)); }
+ static _FORCE_INLINE_ uint32_t hash(const char32_t p_uchar) { return hash_fmix32(p_uchar); }
+ static _FORCE_INLINE_ uint32_t hash(const unsigned p_key) { return hash_fmix32(p_key); }
};
-static _WinTranslatePair _vk_to_keycode[] = {
+HashMap<unsigned int, Key, HashMapHasherKeys> vk_map;
+HashMap<unsigned int, Key, HashMapHasherKeys> scansym_map;
+HashMap<Key, unsigned int, HashMapHasherKeys> scansym_map_inv;
+HashMap<unsigned int, Key, HashMapHasherKeys> scansym_map_ext;
+
+void KeyMappingWindows::initialize() {
// VK_LBUTTON (0x01)
// VK_RBUTTON (0x02)
// VK_CANCEL (0x03)
// VK_MBUTTON (0x04)
// VK_XBUTTON1 (0x05)
- // VK_XBUTTON2 (0x06)
- // We have no mappings for the above, as we only map keyboard buttons here.
-
+ // VK_XBUTTON2 (0x06), We have no mappings for the above;as we only map keyboard buttons here.
// 0x07 is undefined.
-
- { Key::BACKSPACE, VK_BACK }, // (0x08)
- { Key::TAB, VK_TAB }, // (0x09)
-
+ vk_map[VK_BACK] = Key::BACKSPACE; // (0x08)
+ vk_map[VK_TAB] = Key::TAB; // (0x09)
// 0x0A-0B are reserved.
-
- { Key::CLEAR, VK_CLEAR }, // (0x0C)
- { Key::ENTER, VK_RETURN }, // (0x0D)
-
+ vk_map[VK_CLEAR] = Key::CLEAR; // (0x0C)
+ vk_map[VK_RETURN] = Key::ENTER; // (0x0D)
// 0x0E-0F are undefined.
-
- { Key::SHIFT, VK_SHIFT }, // (0x10)
- { Key::CTRL, VK_CONTROL }, // (0x11)
- { Key::ALT, VK_MENU }, // (0x12)
- { Key::PAUSE, VK_PAUSE }, // (0x13)
- { Key::CAPSLOCK, VK_CAPITAL }, // (0x14)
-
- // 0x15-1A are IME keys. We have no mapping.
-
- { Key::ESCAPE, VK_ESCAPE }, // (0x1B)
-
- // 0x1C-1F are IME keys. We have no mapping.
-
- { Key::SPACE, VK_SPACE }, // (0x20)
- { Key::PAGEUP, VK_PRIOR }, // (0x21)
- { Key::PAGEDOWN, VK_NEXT }, // (0x22)
- { Key::END, VK_END }, // (0x23)
- { Key::HOME, VK_HOME }, // (0x24)
- { Key::LEFT, VK_LEFT }, // (0x25)
- { Key::UP, VK_UP }, // (0x26)
- { Key::RIGHT, VK_RIGHT }, // (0x27)
- { Key::DOWN, VK_DOWN }, // (0x28)
-
- // VK_SELECT (0x29)
- // Old select key, e.g. on Digital Equipment Corporation keyboards.
- // Old and uncommon, we have no mapping.
-
- { Key::PRINT, VK_PRINT }, // (0x2A)
- // Old IBM key, modern keyboards use VK_SNAPSHOT. Map to VK_SNAPSHOT.
-
- // VK_EXECUTE (0x2B)
- // Old and uncommon, we have no mapping.
-
- { Key::PRINT, VK_SNAPSHOT }, // (0x2C)
- { Key::INSERT, VK_INSERT }, // (0x2D)
- { Key::KEY_DELETE, VK_DELETE }, // (0x2E)
-
- { Key::HELP, VK_HELP }, // (0x2F)
- // Old and uncommon, but we have a mapping.
-
- { Key::KEY_0, (0x30) }, // 0 key.
- { Key::KEY_1, (0x31) }, // 1 key.
- { Key::KEY_2, (0x32) }, // 2 key.
- { Key::KEY_3, (0x33) }, // 3 key.
- { Key::KEY_4, (0x34) }, // 4 key.
- { Key::KEY_5, (0x35) }, // 5 key.
- { Key::KEY_6, (0x36) }, // 6 key.
- { Key::KEY_7, (0x37) }, // 7 key.
- { Key::KEY_8, (0x38) }, // 8 key.
- { Key::KEY_9, (0x39) }, // 9 key.
+ vk_map[VK_SHIFT] = Key::SHIFT; // (0x10)
+ vk_map[VK_CONTROL] = Key::CTRL; // (0x11)
+ vk_map[VK_MENU] = Key::ALT; // (0x12)
+ vk_map[VK_PAUSE] = Key::PAUSE; // (0x13)
+ vk_map[VK_CAPITAL] = Key::CAPSLOCK; // (0x14)
+ // 0x15-1A are IME keys.
+ vk_map[VK_ESCAPE] = Key::ESCAPE; // (0x1B)
+ // 0x1C-1F are IME keys.
+ vk_map[VK_SPACE] = Key::SPACE; // (0x20)
+ vk_map[VK_PRIOR] = Key::PAGEUP; // (0x21)
+ vk_map[VK_NEXT] = Key::PAGEDOWN; // (0x22)
+ vk_map[VK_END] = Key::END; // (0x23)
+ vk_map[VK_HOME] = Key::HOME; // (0x24)
+ vk_map[VK_LEFT] = Key::LEFT; // (0x25)
+ vk_map[VK_UP] = Key::UP; // (0x26)
+ vk_map[VK_RIGHT] = Key::RIGHT; // (0x27)
+ vk_map[VK_DOWN] = Key::DOWN; // (0x28)
+ // VK_SELECT (0x29), Old select key; e.g. on Digital Equipment Corporation keyboards.
+ vk_map[VK_PRINT] = Key::PRINT; // (0x2A), Old IBM key; modern keyboards use VK_SNAPSHOT.
+ // VK_EXECUTE (0x2B), Old and uncommon.
+ vk_map[VK_SNAPSHOT] = Key::PRINT; // (0x2C)
+ vk_map[VK_INSERT] = Key::INSERT; // (0x2D)
+ vk_map[VK_DELETE] = Key::KEY_DELETE; // (0x2E)
+ vk_map[VK_HELP] = Key::HELP; // (0x2F)
+ vk_map[0x30] = Key::KEY_0; // 0 key.
+ vk_map[0x31] = Key::KEY_1; // 1 key.
+ vk_map[0x32] = Key::KEY_2; // 2 key.
+ vk_map[0x33] = Key::KEY_3; // 3 key.
+ vk_map[0x34] = Key::KEY_4; // 4 key.
+ vk_map[0x35] = Key::KEY_5; // 5 key.
+ vk_map[0x36] = Key::KEY_6; // 6 key.
+ vk_map[0x37] = Key::KEY_7; // 7 key.
+ vk_map[0x38] = Key::KEY_8; // 8 key.
+ vk_map[0x39] = Key::KEY_9; // 9 key.
// 0x3A-40 are undefined.
- { Key::A, (0x41) }, // A key.
- { Key::B, (0x42) }, // B key.
- { Key::C, (0x43) }, // C key.
- { Key::D, (0x44) }, // D key.
- { Key::E, (0x45) }, // E key.
- { Key::F, (0x46) }, // F key.
- { Key::G, (0x47) }, // G key.
- { Key::H, (0x48) }, // H key.
- { Key::I, (0x49) }, // I key
- { Key::J, (0x4A) }, // J key.
- { Key::K, (0x4B) }, // K key.
- { Key::L, (0x4C) }, // L key.
- { Key::M, (0x4D) }, // M key.
- { Key::N, (0x4E) }, // N key.
- { Key::O, (0x4F) }, // O key.
- { Key::P, (0x50) }, // P key.
- { Key::Q, (0x51) }, // Q key.
- { Key::R, (0x52) }, // R key.
- { Key::S, (0x53) }, // S key.
- { Key::T, (0x54) }, // T key.
- { Key::U, (0x55) }, // U key.
- { Key::V, (0x56) }, // V key.
- { Key::W, (0x57) }, // W key.
- { Key::X, (0x58) }, // X key.
- { Key::Y, (0x59) }, // Y key.
- { Key::Z, (0x5A) }, // Z key.
-
- { (Key)KeyModifierMask::META, VK_LWIN }, // (0x5B)
- { (Key)KeyModifierMask::META, VK_RWIN }, // (0x5C)
- { Key::MENU, VK_APPS }, // (0x5D)
+ vk_map[0x41] = Key::A; // A key.
+ vk_map[0x42] = Key::B; // B key.
+ vk_map[0x43] = Key::C; // C key.
+ vk_map[0x44] = Key::D; // D key.
+ vk_map[0x45] = Key::E; // E key.
+ vk_map[0x46] = Key::F; // F key.
+ vk_map[0x47] = Key::G; // G key.
+ vk_map[0x48] = Key::H; // H key.
+ vk_map[0x49] = Key::I; // I key
+ vk_map[0x4A] = Key::J; // J key.
+ vk_map[0x4B] = Key::K; // K key.
+ vk_map[0x4C] = Key::L; // L key.
+ vk_map[0x4D] = Key::M; // M key.
+ vk_map[0x4E] = Key::N; // N key.
+ vk_map[0x4F] = Key::O; // O key.
+ vk_map[0x50] = Key::P; // P key.
+ vk_map[0x51] = Key::Q; // Q key.
+ vk_map[0x52] = Key::R; // R key.
+ vk_map[0x53] = Key::S; // S key.
+ vk_map[0x54] = Key::T; // T key.
+ vk_map[0x55] = Key::U; // U key.
+ vk_map[0x56] = Key::V; // V key.
+ vk_map[0x57] = Key::W; // W key.
+ vk_map[0x58] = Key::X; // X key.
+ vk_map[0x59] = Key::Y; // Y key.
+ vk_map[0x5A] = Key::Z; // Z key.
+ vk_map[VK_LWIN] = (Key)Key::META; // (0x5B)
+ vk_map[VK_RWIN] = (Key)Key::META; // (0x5C)
+ vk_map[VK_APPS] = Key::MENU; // (0x5D)
// 0x5E is reserved.
- { Key::STANDBY, VK_SLEEP }, // (0x5F)
- { Key::KP_0, VK_NUMPAD0 }, // (0x60)
- { Key::KP_1, VK_NUMPAD1 }, // (0x61)
- { Key::KP_2, VK_NUMPAD2 }, // (0x62)
- { Key::KP_3, VK_NUMPAD3 }, // (0x63)
- { Key::KP_4, VK_NUMPAD4 }, // (0x64)
- { Key::KP_5, VK_NUMPAD5 }, // (0x65)
- { Key::KP_6, VK_NUMPAD6 }, // (0x66)
- { Key::KP_7, VK_NUMPAD7 }, // (0x67)
- { Key::KP_8, VK_NUMPAD8 }, // (0x68)
- { Key::KP_9, VK_NUMPAD9 }, // (0x69)
- { Key::KP_MULTIPLY, VK_MULTIPLY }, // (0x6A)
- { Key::KP_ADD, VK_ADD }, // (0x6B)
- { Key::KP_PERIOD, VK_SEPARATOR }, // (0x6C)
- // VK_SEPERATOR (key 0x6C) is not found on US keyboards.
- // It is used on some Brazilian and Far East keyboards.
- // We don't have a direct mapping, map to period.
- { Key::KP_SUBTRACT, VK_SUBTRACT }, // (0x6D)
- { Key::KP_PERIOD, VK_DECIMAL }, // (0x6E)
- { Key::KP_DIVIDE, VK_DIVIDE }, // (0x6F)
- { Key::F1, VK_F1 }, // (0x70)
- { Key::F2, VK_F2 }, // (0x71)
- { Key::F3, VK_F3 }, // (0x72)
- { Key::F4, VK_F4 }, // (0x73)
- { Key::F5, VK_F5 }, // (0x74)
- { Key::F6, VK_F6 }, // (0x75)
- { Key::F7, VK_F7 }, // (0x76)
- { Key::F8, VK_F8 }, // (0x77)
- { Key::F9, VK_F9 }, // (0x78)
- { Key::F10, VK_F10 }, // (0x79)
- { Key::F11, VK_F11 }, // (0x7A)
- { Key::F12, VK_F12 }, // (0x7B)
- { Key::F13, VK_F13 }, // (0x7C)
- { Key::F14, VK_F14 }, // (0x7D)
- { Key::F15, VK_F15 }, // (0x7E)
- { Key::F16, VK_F16 }, // (0x7F)
- { Key::F17, VK_F17 }, // (0x80)
- { Key::F18, VK_F18 }, // (0x81)
- { Key::F19, VK_F19 }, // (0x82)
- { Key::F20, VK_F20 }, // (0x83)
- { Key::F21, VK_F21 }, // (0x84)
- { Key::F22, VK_F22 }, // (0x85)
- { Key::F23, VK_F23 }, // (0x86)
- { Key::F24, VK_F24 }, // (0x87)
+ vk_map[VK_SLEEP] = Key::STANDBY; // (0x5F)
+ vk_map[VK_NUMPAD0] = Key::KP_0; // (0x60)
+ vk_map[VK_NUMPAD1] = Key::KP_1; // (0x61)
+ vk_map[VK_NUMPAD2] = Key::KP_2; // (0x62)
+ vk_map[VK_NUMPAD3] = Key::KP_3; // (0x63)
+ vk_map[VK_NUMPAD4] = Key::KP_4; // (0x64)
+ vk_map[VK_NUMPAD5] = Key::KP_5; // (0x65)
+ vk_map[VK_NUMPAD6] = Key::KP_6; // (0x66)
+ vk_map[VK_NUMPAD7] = Key::KP_7; // (0x67)
+ vk_map[VK_NUMPAD8] = Key::KP_8; // (0x68)
+ vk_map[VK_NUMPAD9] = Key::KP_9; // (0x69)
+ vk_map[VK_MULTIPLY] = Key::KP_MULTIPLY; // (0x6A)
+ vk_map[VK_ADD] = Key::KP_ADD; // (0x6B)
+ vk_map[VK_SEPARATOR] = Key::KP_PERIOD; // (0x6C)
+ vk_map[VK_SUBTRACT] = Key::KP_SUBTRACT; // (0x6D)
+ vk_map[VK_DECIMAL] = Key::KP_PERIOD; // (0x6E)
+ vk_map[VK_DIVIDE] = Key::KP_DIVIDE; // (0x6F)
+ vk_map[VK_F1] = Key::F1; // (0x70)
+ vk_map[VK_F2] = Key::F2; // (0x71)
+ vk_map[VK_F3] = Key::F3; // (0x72)
+ vk_map[VK_F4] = Key::F4; // (0x73)
+ vk_map[VK_F5] = Key::F5; // (0x74)
+ vk_map[VK_F6] = Key::F6; // (0x75)
+ vk_map[VK_F7] = Key::F7; // (0x76)
+ vk_map[VK_F8] = Key::F8; // (0x77)
+ vk_map[VK_F9] = Key::F9; // (0x78)
+ vk_map[VK_F10] = Key::F10; // (0x79)
+ vk_map[VK_F11] = Key::F11; // (0x7A)
+ vk_map[VK_F12] = Key::F12; // (0x7B)
+ vk_map[VK_F13] = Key::F13; // (0x7C)
+ vk_map[VK_F14] = Key::F14; // (0x7D)
+ vk_map[VK_F15] = Key::F15; // (0x7E)
+ vk_map[VK_F16] = Key::F16; // (0x7F)
+ vk_map[VK_F17] = Key::F17; // (0x80)
+ vk_map[VK_F18] = Key::F18; // (0x81)
+ vk_map[VK_F19] = Key::F19; // (0x82)
+ vk_map[VK_F20] = Key::F20; // (0x83)
+ vk_map[VK_F21] = Key::F21; // (0x84)
+ vk_map[VK_F22] = Key::F22; // (0x85)
+ vk_map[VK_F23] = Key::F23; // (0x86)
+ vk_map[VK_F24] = Key::F24; // (0x87)
// 0x88-8F are reserved for UI navigation.
- { Key::NUMLOCK, VK_NUMLOCK }, // (0x90)
- { Key::SCROLLLOCK, VK_SCROLL }, // (0x91)
-
- { Key::EQUAL, VK_OEM_NEC_EQUAL }, // (0x92)
- // OEM NEC PC-9800 numpad '=' key.
-
- // 0x93-96 are OEM specific (e.g. used by Fujitsu/OASYS), we have no mappings.
+ vk_map[VK_NUMLOCK] = Key::NUMLOCK; // (0x90)
+ vk_map[VK_SCROLL] = Key::SCROLLLOCK; // (0x91)
+ vk_map[VK_OEM_NEC_EQUAL] = Key::EQUAL; // (0x92), OEM NEC PC-9800 numpad '=' key.
+ // 0x93-96 are OEM specific (e.g. used by Fujitsu/OASYS);
// 0x97-9F are unassigned.
-
- { Key::SHIFT, VK_LSHIFT }, // (0xA0)
- { Key::SHIFT, VK_RSHIFT }, // (0xA1)
- { Key::CTRL, VK_LCONTROL }, // (0xA2)
- { Key::CTRL, VK_RCONTROL }, // (0xA3)
- { Key::MENU, VK_LMENU }, // (0xA4)
- { Key::MENU, VK_RMENU }, // (0xA5)
-
- { Key::BACK, VK_BROWSER_BACK }, // (0xA6)
- { Key::FORWARD, VK_BROWSER_FORWARD }, // (0xA7)
- { Key::REFRESH, VK_BROWSER_REFRESH }, // (0xA8)
- { Key::STOP, VK_BROWSER_STOP }, // (0xA9)
- { Key::SEARCH, VK_BROWSER_SEARCH }, // (0xAA)
- { Key::FAVORITES, VK_BROWSER_FAVORITES }, // (0xAB)
- { Key::HOMEPAGE, VK_BROWSER_HOME }, // (0xAC)
- { Key::VOLUMEMUTE, VK_VOLUME_MUTE }, // (0xAD)
- { Key::VOLUMEDOWN, VK_VOLUME_DOWN }, // (0xAE)
- { Key::VOLUMEUP, VK_VOLUME_UP }, // (0xAF)
- { Key::MEDIANEXT, VK_MEDIA_NEXT_TRACK }, // (0xB0)
- { Key::MEDIAPREVIOUS, VK_MEDIA_PREV_TRACK }, // (0xB1)
- { Key::MEDIASTOP, VK_MEDIA_STOP }, // (0xB2)
-
- { Key::MEDIAPLAY, VK_MEDIA_PLAY_PAUSE }, // (0xB3)
- // Media button play/pause toggle.
- // Map to media play (there is no other 'play' mapping on Windows).
-
- { Key::LAUNCHMAIL, VK_LAUNCH_MAIL }, // (0xB4)
- { Key::LAUNCHMEDIA, VK_LAUNCH_MEDIA_SELECT }, // (0xB5)
- { Key::LAUNCH0, VK_LAUNCH_APP1 }, // (0xB6)
- { Key::LAUNCH1, VK_LAUNCH_APP2 }, // (0xB7)
-
+ vk_map[VK_LSHIFT] = Key::SHIFT; // (0xA0)
+ vk_map[VK_RSHIFT] = Key::SHIFT; // (0xA1)
+ vk_map[VK_LCONTROL] = Key::CTRL; // (0xA2)
+ vk_map[VK_RCONTROL] = Key::CTRL; // (0xA3)
+ vk_map[VK_LMENU] = Key::MENU; // (0xA4)
+ vk_map[VK_RMENU] = Key::MENU; // (0xA5)
+ vk_map[VK_BROWSER_BACK] = Key::BACK; // (0xA6)
+ vk_map[VK_BROWSER_FORWARD] = Key::FORWARD; // (0xA7)
+ vk_map[VK_BROWSER_REFRESH] = Key::REFRESH; // (0xA8)
+ vk_map[VK_BROWSER_STOP] = Key::STOP; // (0xA9)
+ vk_map[VK_BROWSER_SEARCH] = Key::SEARCH; // (0xAA)
+ vk_map[VK_BROWSER_FAVORITES] = Key::FAVORITES; // (0xAB)
+ vk_map[VK_BROWSER_HOME] = Key::HOMEPAGE; // (0xAC)
+ vk_map[VK_VOLUME_MUTE] = Key::VOLUMEMUTE; // (0xAD)
+ vk_map[VK_VOLUME_DOWN] = Key::VOLUMEDOWN; // (0xAE)
+ vk_map[VK_VOLUME_UP] = Key::VOLUMEUP; // (0xAF)
+ vk_map[VK_MEDIA_NEXT_TRACK] = Key::MEDIANEXT; // (0xB0)
+ vk_map[VK_MEDIA_PREV_TRACK] = Key::MEDIAPREVIOUS; // (0xB1)
+ vk_map[VK_MEDIA_STOP] = Key::MEDIASTOP; // (0xB2)
+ vk_map[VK_MEDIA_PLAY_PAUSE] = Key::MEDIAPLAY; // (0xB3), Media button play/pause toggle.
+ vk_map[VK_LAUNCH_MAIL] = Key::LAUNCHMAIL; // (0xB4)
+ vk_map[VK_LAUNCH_MEDIA_SELECT] = Key::LAUNCHMEDIA; // (0xB5)
+ vk_map[VK_LAUNCH_APP1] = Key::LAUNCH0; // (0xB6)
+ vk_map[VK_LAUNCH_APP2] = Key::LAUNCH1; // (0xB7)
// 0xB8-B9 are reserved.
-
- { Key::SEMICOLON, VK_OEM_1 }, // (0xBA)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, the ';:' key.
-
- { Key::EQUAL, VK_OEM_PLUS }, // (0xBB)
- // Windows 2000/XP: For any country/region, the '+' key.
- { Key::COMMA, VK_OEM_COMMA }, // (0xBC)
- // Windows 2000/XP: For any country/region, the ',' key.
- { Key::MINUS, VK_OEM_MINUS }, // (0xBD)
- // Windows 2000/XP: For any country/region, the '-' key.
- { Key::PERIOD, VK_OEM_PERIOD }, // (0xBE)
- // Windows 2000/XP: For any country/region, the '.' key.
-
- { Key::SLASH, VK_OEM_2 }, // (0xBF)
- // Windows 2000/XP: For US standard keyboards, the '/?' key.
-
- { Key::QUOTELEFT, VK_OEM_3 }, // (0xC0)
- // Windows 2000/XP: For US standard keyboards, the '`~' key.
-
+ vk_map[VK_OEM_1] = Key::SEMICOLON; // (0xBA), Misc. character;can vary by keyboard/region. For US standard keyboards;the ';:' key.
+ vk_map[VK_OEM_PLUS] = Key::EQUAL; // (0xBB)
+ vk_map[VK_OEM_COMMA] = Key::COMMA; // (0xBC)
+ vk_map[VK_OEM_MINUS] = Key::MINUS; // (0xBD)
+ vk_map[VK_OEM_PERIOD] = Key::PERIOD; // (0xBE)
+ vk_map[VK_OEM_2] = Key::SLASH; // (0xBF), For US standard keyboards;the '/?' key.
+ vk_map[VK_OEM_3] = Key::QUOTELEFT; // (0xC0), For US standard keyboards;the '`~' key.
// 0xC1-D7 are reserved. 0xD8-DA are unassigned.
- // TODO: 0xC3-DA may be used for old gamepads? Maybe we want to support this? See WinUser.h.
-
- { Key::BRACKETLEFT, VK_OEM_4 }, // (0xDB)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, the '[{' key.
-
- { Key::BACKSLASH, VK_OEM_5 }, // (0xDC)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, the '\|' key.
-
- { Key::BRACKETRIGHT, VK_OEM_6 }, // (0xDD)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, the ']}' key.
-
- { Key::APOSTROPHE, VK_OEM_7 }, // (0xDE)
- // Misc. character, can vary by keyboard/region.
- // Windows 2000/XP: For US standard keyboards, single quote/double quote.
-
+ // 0xC3-DA may be used for old gamepads? Maybe we want to support this? See WinUser.h.
+ vk_map[VK_OEM_4] = Key::BRACKETLEFT; // (0xDB), For US standard keyboards;the '[{' key.
+ vk_map[VK_OEM_5] = Key::BACKSLASH; // (0xDC), For US standard keyboards;the '\|' key.
+ vk_map[VK_OEM_6] = Key::BRACKETRIGHT; // (0xDD), For US standard keyboards;the ']}' key.
+ vk_map[VK_OEM_7] = Key::APOSTROPHE; // (0xDE), For US standard keyboards;single quote/double quote.
// VK_OEM_8 (0xDF)
- // Misc. character, can vary by keyboard/region. We have no mapping.
-
- // 0xE0 is reserved. 0xE1 is OEM specific, we have no mapping.
-
- // VK_OEM_102 (0xE2)
- // Either angle bracket or backslash key on the RT 102-key keyboard.
- // Old and uncommon, we have no mapping.
-
- { Key::HELP, VK_ICO_HELP }, // (0xE3)
- // OEM (ICO) help key. Map to help.
-
- // 0xE4 is OEM (e.g. ICO) specific, we have no mapping.
-
- // VK_PROCESSKEY (0xE5)
- // For IME, we have no mapping.
-
- { Key::CLEAR, VK_ICO_CLEAR }, // (0xE6)
- // OEM (ICO) clear key. Map to clear.
-
- // VK_PACKET (0xE7)
- // Used to pass Unicode characters as if they were keystrokes.
- // See Win32 API docs. We have no mapping.
-
- // 0xE8 is unassigned, 0xE9-F5 are OEM (Nokia/Ericsson) specific, we have no mappings.
-
- { Key::ESCAPE, VK_ATTN }, // (0xF6)
- // Old IBM 'ATTN' key used on midrange computers, e.g. AS/400, map to Escape.
-
- { Key::TAB, VK_CRSEL }, // (0xF7)
- // Old IBM 3270 'CrSel' (cursor select) key, used to select data fields, map to Tab.
-
- // VK_EXSEL (0xF7)
- // Old IBM 3270 extended selection key. No mapping.
-
- // VK_EREOF (0xF8)
- // Old IBM 3270 erase to end of field key. No mapping.
-
- { Key::MEDIAPLAY, VK_PLAY }, // (0xFA)
- // Old IBM 3270 'Play' key. Map to media play.
-
- // VK_ZOOM (0xFB)
- // Old IBM 3290 'Zoom' key. No mapping.
-
- // VK_NONAME (0xFC)
- // Reserved. No mapping.
-
- // VK_PA1 (0xFD)
- // Old IBM 3270 PA1 key. No mapping.
-
- { Key::CLEAR, VK_OEM_CLEAR }, // (0xFE)
- // OEM specific clear key. Unclear how it differs from normal clear. Map to clear.
-
- { Key::UNKNOWN, 0 }
-};
+ // 0xE0 is reserved. 0xE1 is OEM specific.
+ vk_map[VK_OEM_102] = Key::BAR; // (0xE2), Either angle bracket or backslash key on the RT 102-key keyboard.
+ vk_map[VK_ICO_HELP] = Key::HELP; // (0xE3)
+ // 0xE4 is OEM (e.g. ICO) specific.
+ // VK_PROCESSKEY (0xE5), For IME.
+ vk_map[VK_ICO_CLEAR] = Key::CLEAR; // (0xE6)
+ // VK_PACKET (0xE7), Used to pass Unicode characters as if they were keystrokes.
+ // 0xE8 is unassigned.
+ // 0xE9-F5 are OEM (Nokia/Ericsson) specific.
+ vk_map[VK_ATTN] = Key::ESCAPE; // (0xF6), Old IBM 'ATTN' key used on midrange computers ;e.g. AS/400.
+ vk_map[VK_CRSEL] = Key::TAB; // (0xF7), Old IBM 3270 'CrSel' (cursor select) key; used to select data fields.
+ // VK_EXSEL (0xF7), Old IBM 3270 extended selection key.
+ // VK_EREOF (0xF8), Old IBM 3270 erase to end of field key.
+ vk_map[VK_PLAY] = Key::MEDIAPLAY; // (0xFA), Old IBM 3270 'Play' key.
+ // VK_ZOOM (0xFB), Old IBM 3290 'Zoom' key.
+ // VK_NONAME (0xFC), Reserved.
+ // VK_PA1 (0xFD), Old IBM 3270 PA1 key.
+ vk_map[VK_OEM_CLEAR] = Key::CLEAR; // (0xFE), OEM specific clear key. Unclear how it differs from normal clear.
+
+ scansym_map[0x00] = Key::PAUSE;
+ scansym_map[0x01] = Key::ESCAPE;
+ scansym_map[0x02] = Key::KEY_1;
+ scansym_map[0x03] = Key::KEY_2;
+ scansym_map[0x04] = Key::KEY_3;
+ scansym_map[0x05] = Key::KEY_4;
+ scansym_map[0x06] = Key::KEY_5;
+ scansym_map[0x07] = Key::KEY_6;
+ scansym_map[0x08] = Key::KEY_7;
+ scansym_map[0x09] = Key::KEY_8;
+ scansym_map[0x0A] = Key::KEY_9;
+ scansym_map[0x0B] = Key::KEY_0;
+ scansym_map[0x0C] = Key::MINUS;
+ scansym_map[0x0D] = Key::EQUAL;
+ scansym_map[0x0E] = Key::BACKSPACE;
+ scansym_map[0x0F] = Key::TAB;
+ scansym_map[0x10] = Key::Q;
+ scansym_map[0x11] = Key::W;
+ scansym_map[0x12] = Key::E;
+ scansym_map[0x13] = Key::R;
+ scansym_map[0x14] = Key::T;
+ scansym_map[0x15] = Key::Y;
+ scansym_map[0x16] = Key::U;
+ scansym_map[0x17] = Key::I;
+ scansym_map[0x18] = Key::O;
+ scansym_map[0x19] = Key::P;
+ scansym_map[0x1A] = Key::BRACELEFT;
+ scansym_map[0x1B] = Key::BRACERIGHT;
+ scansym_map[0x1C] = Key::ENTER;
+ scansym_map[0x1D] = Key::CTRL;
+ scansym_map[0x1E] = Key::A;
+ scansym_map[0x1F] = Key::S;
+ scansym_map[0x20] = Key::D;
+ scansym_map[0x21] = Key::F;
+ scansym_map[0x22] = Key::G;
+ scansym_map[0x23] = Key::H;
+ scansym_map[0x24] = Key::J;
+ scansym_map[0x25] = Key::K;
+ scansym_map[0x26] = Key::L;
+ scansym_map[0x27] = Key::SEMICOLON;
+ scansym_map[0x28] = Key::APOSTROPHE;
+ scansym_map[0x29] = Key::QUOTELEFT;
+ scansym_map[0x2A] = Key::SHIFT;
+ scansym_map[0x2B] = Key::BACKSLASH;
+ scansym_map[0x2C] = Key::Z;
+ scansym_map[0x2D] = Key::X;
+ scansym_map[0x2E] = Key::C;
+ scansym_map[0x2F] = Key::V;
+ scansym_map[0x30] = Key::B;
+ scansym_map[0x31] = Key::N;
+ scansym_map[0x32] = Key::M;
+ scansym_map[0x33] = Key::COMMA;
+ scansym_map[0x34] = Key::PERIOD;
+ scansym_map[0x35] = Key::SLASH;
+ scansym_map[0x36] = Key::SHIFT;
+ scansym_map[0x37] = Key::KP_MULTIPLY;
+ scansym_map[0x38] = Key::ALT;
+ scansym_map[0x39] = Key::SPACE;
+ scansym_map[0x3A] = Key::CAPSLOCK;
+ scansym_map[0x3B] = Key::F1;
+ scansym_map[0x3C] = Key::F2;
+ scansym_map[0x3D] = Key::F3;
+ scansym_map[0x3E] = Key::F4;
+ scansym_map[0x3F] = Key::F5;
+ scansym_map[0x40] = Key::F6;
+ scansym_map[0x41] = Key::F7;
+ scansym_map[0x42] = Key::F8;
+ scansym_map[0x43] = Key::F9;
+ scansym_map[0x44] = Key::F10;
+ scansym_map[0x45] = Key::NUMLOCK;
+ scansym_map[0x46] = Key::SCROLLLOCK;
+ scansym_map[0x47] = Key::KP_7;
+ scansym_map[0x48] = Key::KP_8;
+ scansym_map[0x49] = Key::KP_9;
+ scansym_map[0x4A] = Key::KP_SUBTRACT;
+ scansym_map[0x4B] = Key::KP_4;
+ scansym_map[0x4C] = Key::KP_5;
+ scansym_map[0x4D] = Key::KP_6;
+ scansym_map[0x4E] = Key::KP_ADD;
+ scansym_map[0x4F] = Key::KP_1;
+ scansym_map[0x50] = Key::KP_2;
+ scansym_map[0x51] = Key::KP_3;
+ scansym_map[0x52] = Key::KP_0;
+ scansym_map[0x53] = Key::KP_PERIOD;
+ scansym_map[0x57] = Key::SECTION;
+ scansym_map[0x57] = Key::F11;
+ scansym_map[0x58] = Key::F12;
+ scansym_map[0x5B] = Key::META;
+ scansym_map[0x5C] = Key::META;
+ scansym_map[0x5D] = Key::MENU;
+ scansym_map[0x64] = Key::F13;
+ scansym_map[0x65] = Key::F14;
+ scansym_map[0x66] = Key::F15;
+ scansym_map[0x67] = Key::F16;
+ scansym_map[0x68] = Key::F17;
+ scansym_map[0x69] = Key::F18;
+ scansym_map[0x6A] = Key::F19;
+ scansym_map[0x6B] = Key::F20;
+ scansym_map[0x6C] = Key::F21;
+ scansym_map[0x6D] = Key::F22;
+ scansym_map[0x6E] = Key::F23;
+ // scansym_map[0x71] = Key::JIS_KANA;
+ // scansym_map[0x72] = Key::JIS_EISU;
+ scansym_map[0x76] = Key::F24;
+
+ for (const KeyValue<unsigned int, Key> &E : scansym_map) {
+ scansym_map_inv[E.value] = E.key;
+ }
-static _WinTranslatePair _scancode_to_keycode[] = {
- { Key::ESCAPE, 0x01 },
- { Key::KEY_1, 0x02 },
- { Key::KEY_2, 0x03 },
- { Key::KEY_3, 0x04 },
- { Key::KEY_4, 0x05 },
- { Key::KEY_5, 0x06 },
- { Key::KEY_6, 0x07 },
- { Key::KEY_7, 0x08 },
- { Key::KEY_8, 0x09 },
- { Key::KEY_9, 0x0A },
- { Key::KEY_0, 0x0B },
- { Key::MINUS, 0x0C },
- { Key::EQUAL, 0x0D },
- { Key::BACKSPACE, 0x0E },
- { Key::TAB, 0x0F },
- { Key::Q, 0x10 },
- { Key::W, 0x11 },
- { Key::E, 0x12 },
- { Key::R, 0x13 },
- { Key::T, 0x14 },
- { Key::Y, 0x15 },
- { Key::U, 0x16 },
- { Key::I, 0x17 },
- { Key::O, 0x18 },
- { Key::P, 0x19 },
- { Key::BRACELEFT, 0x1A },
- { Key::BRACERIGHT, 0x1B },
- { Key::ENTER, 0x1C },
- { Key::CTRL, 0x1D },
- { Key::A, 0x1E },
- { Key::S, 0x1F },
- { Key::D, 0x20 },
- { Key::F, 0x21 },
- { Key::G, 0x22 },
- { Key::H, 0x23 },
- { Key::J, 0x24 },
- { Key::K, 0x25 },
- { Key::L, 0x26 },
- { Key::SEMICOLON, 0x27 },
- { Key::APOSTROPHE, 0x28 },
- { Key::QUOTELEFT, 0x29 },
- { Key::SHIFT, 0x2A },
- { Key::BACKSLASH, 0x2B },
- { Key::Z, 0x2C },
- { Key::X, 0x2D },
- { Key::C, 0x2E },
- { Key::V, 0x2F },
- { Key::B, 0x30 },
- { Key::N, 0x31 },
- { Key::M, 0x32 },
- { Key::COMMA, 0x33 },
- { Key::PERIOD, 0x34 },
- { Key::SLASH, 0x35 },
- { Key::SHIFT, 0x36 },
- { Key::PRINT, 0x37 },
- { Key::ALT, 0x38 },
- { Key::SPACE, 0x39 },
- { Key::CAPSLOCK, 0x3A },
- { Key::F1, 0x3B },
- { Key::F2, 0x3C },
- { Key::F3, 0x3D },
- { Key::F4, 0x3E },
- { Key::F5, 0x3F },
- { Key::F6, 0x40 },
- { Key::F7, 0x41 },
- { Key::F8, 0x42 },
- { Key::F9, 0x43 },
- { Key::F10, 0x44 },
- { Key::NUMLOCK, 0x45 },
- { Key::SCROLLLOCK, 0x46 },
- { Key::HOME, 0x47 },
- { Key::UP, 0x48 },
- { Key::PAGEUP, 0x49 },
- { Key::KP_SUBTRACT, 0x4A },
- { Key::LEFT, 0x4B },
- { Key::KP_5, 0x4C },
- { Key::RIGHT, 0x4D },
- { Key::KP_ADD, 0x4E },
- { Key::END, 0x4F },
- { Key::DOWN, 0x50 },
- { Key::PAGEDOWN, 0x51 },
- { Key::INSERT, 0x52 },
- { Key::KEY_DELETE, 0x53 },
- { Key::F11, 0x57 },
- { Key::F12, 0x58 },
- { Key::META, 0x5B },
- { Key::META, 0x5C },
- { Key::MENU, 0x5D },
- { Key::F13, 0x64 },
- { Key::F14, 0x65 },
- { Key::F15, 0x66 },
- { Key::F16, 0x67 },
- { Key::F17, 0x68 },
- { Key::F18, 0x69 },
- { Key::F19, 0x6A },
- { Key::F20, 0x6B },
- { Key::F21, 0x6C },
- { Key::F22, 0x6D },
- { Key::F23, 0x6E },
- { Key::F24, 0x76 },
- { Key::UNKNOWN, 0 }
-};
+ scansym_map_ext[0x09] = Key::MENU;
+ scansym_map_ext[0x10] = Key::MEDIAPREVIOUS;
+ scansym_map_ext[0x19] = Key::MEDIANEXT;
+ scansym_map_ext[0x1C] = Key::KP_ENTER;
+ scansym_map_ext[0x20] = Key::VOLUMEMUTE;
+ scansym_map_ext[0x21] = Key::LAUNCH1;
+ scansym_map_ext[0x22] = Key::MEDIAPLAY;
+ scansym_map_ext[0x24] = Key::MEDIASTOP;
+ scansym_map_ext[0x2E] = Key::VOLUMEDOWN;
+ scansym_map_ext[0x30] = Key::VOLUMEUP;
+ scansym_map_ext[0x32] = Key::HOMEPAGE;
+ scansym_map_ext[0x35] = Key::KP_DIVIDE;
+ scansym_map_ext[0x37] = Key::PRINT;
+ scansym_map_ext[0x3A] = Key::KP_ADD;
+ scansym_map_ext[0x45] = Key::NUMLOCK;
+ scansym_map_ext[0x47] = Key::HOME;
+ scansym_map_ext[0x48] = Key::UP;
+ scansym_map_ext[0x49] = Key::PAGEUP;
+ scansym_map_ext[0x4A] = Key::KP_SUBTRACT;
+ scansym_map_ext[0x4B] = Key::LEFT;
+ scansym_map_ext[0x4C] = Key::KP_5;
+ scansym_map_ext[0x4D] = Key::RIGHT;
+ scansym_map_ext[0x4E] = Key::KP_ADD;
+ scansym_map_ext[0x4F] = Key::END;
+ scansym_map_ext[0x50] = Key::DOWN;
+ scansym_map_ext[0x51] = Key::PAGEDOWN;
+ scansym_map_ext[0x52] = Key::INSERT;
+ scansym_map_ext[0x53] = Key::KEY_DELETE;
+ scansym_map_ext[0x5D] = Key::MENU;
+ scansym_map_ext[0x5F] = Key::STANDBY;
+ scansym_map_ext[0x65] = Key::SEARCH;
+ scansym_map_ext[0x66] = Key::FAVORITES;
+ scansym_map_ext[0x67] = Key::REFRESH;
+ scansym_map_ext[0x68] = Key::STOP;
+ scansym_map_ext[0x69] = Key::FORWARD;
+ scansym_map_ext[0x6A] = Key::BACK;
+ scansym_map_ext[0x6B] = Key::LAUNCH0;
+ scansym_map_ext[0x6C] = Key::LAUNCHMAIL;
+ scansym_map_ext[0x6D] = Key::LAUNCHMEDIA;
+ scansym_map_ext[0x78] = Key::MEDIARECORD;
+}
Key KeyMappingWindows::get_keysym(unsigned int p_code) {
- for (int i = 0; _vk_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_vk_to_keycode[i].keycode == p_code) {
- return _vk_to_keycode[i].keysym;
- }
+ const Key *key = vk_map.getptr(p_code);
+ if (key) {
+ return *key;
}
-
return Key::UNKNOWN;
}
unsigned int KeyMappingWindows::get_scancode(Key p_keycode) {
- for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_scancode_to_keycode[i].keysym == p_keycode) {
- return _scancode_to_keycode[i].keycode;
- }
+ const unsigned int *key = scansym_map_inv.getptr(p_keycode);
+ if (key) {
+ return *key;
}
-
return 0;
}
Key KeyMappingWindows::get_scansym(unsigned int p_code, bool p_extended) {
- Key keycode = Key::UNKNOWN;
- for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_scancode_to_keycode[i].keycode == p_code) {
- keycode = _scancode_to_keycode[i].keysym;
- break;
- }
- }
-
if (p_extended) {
- switch (keycode) {
- case Key::ENTER: {
- keycode = Key::KP_ENTER;
- } break;
- case Key::SLASH: {
- keycode = Key::KP_DIVIDE;
- } break;
- case Key::CAPSLOCK: {
- keycode = Key::KP_ADD;
- } break;
- default:
- break;
- }
- } else {
- switch (keycode) {
- case Key::NUMLOCK: {
- keycode = Key::PAUSE;
- } break;
- case Key::HOME: {
- keycode = Key::KP_7;
- } break;
- case Key::UP: {
- keycode = Key::KP_8;
- } break;
- case Key::PAGEUP: {
- keycode = Key::KP_9;
- } break;
- case Key::LEFT: {
- keycode = Key::KP_4;
- } break;
- case Key::RIGHT: {
- keycode = Key::KP_6;
- } break;
- case Key::END: {
- keycode = Key::KP_1;
- } break;
- case Key::DOWN: {
- keycode = Key::KP_2;
- } break;
- case Key::PAGEDOWN: {
- keycode = Key::KP_3;
- } break;
- case Key::INSERT: {
- keycode = Key::KP_0;
- } break;
- case Key::KEY_DELETE: {
- keycode = Key::KP_PERIOD;
- } break;
- case Key::PRINT: {
- keycode = Key::KP_MULTIPLY;
- } break;
- default:
- break;
+ const Key *key = scansym_map_ext.getptr(p_code);
+ if (key) {
+ return *key;
}
}
-
- return keycode;
+ const Key *key = scansym_map.getptr(p_code);
+ if (key) {
+ return *key;
+ }
+ return Key::NONE;
}
bool KeyMappingWindows::is_extended_key(unsigned int p_code) {
diff --git a/platform/windows/key_mapping_windows.h b/platform/windows/key_mapping_windows.h
index ef5bec2b76..a98aa7ed68 100644
--- a/platform/windows/key_mapping_windows.h
+++ b/platform/windows/key_mapping_windows.h
@@ -41,6 +41,8 @@ class KeyMappingWindows {
KeyMappingWindows() {}
public:
+ static void initialize();
+
static Key get_keysym(unsigned int p_code);
static unsigned int get_scancode(Key p_keycode);
static Key get_scansym(unsigned int p_code, bool p_extended);
diff --git a/platform/windows/logo.png b/platform/windows/logo.png
deleted file mode 100644
index f06b463850..0000000000
--- a/platform/windows/logo.png
+++ /dev/null
Binary files differ
diff --git a/platform/windows/logo.svg b/platform/windows/logo.svg
new file mode 100644
index 0000000000..77a0b20766
--- /dev/null
+++ b/platform/windows/logo.svg
@@ -0,0 +1 @@
+<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg"><path d="m1 5.132 12.295-1.694v11.879H1zm0 21.736 12.295 1.695V16.83H1zm13.647 1.875L31 31V16.83H14.647zm0-25.486v12.06H31V1z" fill="#00abed"/></svg>
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 2a44a19085..d384049fb5 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -210,6 +210,8 @@ void OS_Windows::initialize() {
} else if (!dwrite2_init) {
print_verbose("Unable to load IDWriteFactory2, automatic system font fallback is disabled.");
}
+
+ FileAccessWindows::initialize();
}
void OS_Windows::delete_main_loop() {
@@ -252,6 +254,8 @@ void OS_Windows::finalize() {
}
void OS_Windows::finalize_core() {
+ FileAccessWindows::finalize();
+
timeEndPeriod(1);
memdelete(process_map);
@@ -718,15 +722,23 @@ Error OS_Windows::create_process(const String &p_path, const List<String> &p_arg
}
Error OS_Windows::kill(const ProcessID &p_pid) {
- ERR_FAIL_COND_V(!process_map->has(p_pid), FAILED);
+ int ret = 0;
+ if (process_map->has(p_pid)) {
+ const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi;
+ process_map->erase(p_pid);
- const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi;
- process_map->erase(p_pid);
+ ret = TerminateProcess(pi.hProcess, 0);
- const int ret = TerminateProcess(pi.hProcess, 0);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ } else {
+ HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, false, (DWORD)p_pid);
+ if (hProcess != NULL) {
+ ret = TerminateProcess(hProcess, 0);
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
+ CloseHandle(hProcess);
+ }
+ }
return ret != 0 ? OK : FAILED;
}
@@ -818,7 +830,7 @@ class FallbackTextAnalysisSource : public IDWriteTextAnalysisSource {
IDWriteNumberSubstitution *n_sub = nullptr;
public:
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) {
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) override {
if (IID_IUnknown == riid) {
AddRef();
*ppvInterface = (IUnknown *)this;
@@ -832,11 +844,11 @@ public:
return S_OK;
}
- ULONG STDMETHODCALLTYPE AddRef() {
+ ULONG STDMETHODCALLTYPE AddRef() override {
return InterlockedIncrement(&_cRef);
}
- ULONG STDMETHODCALLTYPE Release() {
+ ULONG STDMETHODCALLTYPE Release() override {
ULONG ulRef = InterlockedDecrement(&_cRef);
if (0 == ulRef) {
delete this;
@@ -1158,17 +1170,24 @@ String OS_Windows::get_environment(const String &p_var) const {
return "";
}
-bool OS_Windows::set_environment(const String &p_var, const String &p_value) const {
- return (bool)SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), (LPCWSTR)(p_value.utf16().get_data()));
+void OS_Windows::set_environment(const String &p_var, const String &p_value) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ Char16String var = p_var.utf16();
+ Char16String value = p_value.utf16();
+ ERR_FAIL_COND_MSG(var.length() + value.length() + 2 > 32767, vformat("Invalid definition for environment variable '%s', cannot exceed 32767 characters.", p_var));
+ SetEnvironmentVariableW((LPCWSTR)(var.get_data()), (LPCWSTR)(value.get_data()));
}
-String OS_Windows::get_stdin_string(bool p_block) {
- if (p_block) {
- WCHAR buff[1024];
- DWORD count = 0;
- if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) {
- return String::utf16((const char16_t *)buff, count);
- }
+void OS_Windows::unset_environment(const String &p_var) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete.
+}
+
+String OS_Windows::get_stdin_string() {
+ WCHAR buff[1024];
+ DWORD count = 0;
+ if (ReadConsoleW(GetStdHandle(STD_INPUT_HANDLE), buff, 1024, &count, nullptr)) {
+ return String::utf16((const char16_t *)buff, count);
}
return String();
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 9cb3977030..05110c2614 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -140,7 +140,7 @@ protected:
virtual void finalize() override;
virtual void finalize_core() override;
- virtual String get_stdin_string(bool p_block) override;
+ virtual String get_stdin_string() override;
String _quote_command_line_argument(const String &p_text) const;
@@ -186,7 +186,8 @@ public:
virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
- virtual bool set_environment(const String &p_var, const String &p_value) const override;
+ virtual void set_environment(const String &p_var, const String &p_value) const override;
+ virtual void unset_environment(const String &p_var) const override;
virtual Vector<String> get_system_fonts() const override;
virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
diff --git a/platform/windows/run_icon.svg b/platform/windows/run_icon.svg
new file mode 100644
index 0000000000..0897276ef7
--- /dev/null
+++ b/platform/windows/run_icon.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m1.095 2.997 5.66-.78v5.469h-5.66zm0 10.006 5.66.78v-5.4h-5.66zm6.282.863 7.528 1.04V8.381H7.377Zm0-11.732v5.552h7.528V1.095Z" fill="#00abed" style="stroke-width:.460341;fill:#e0e0e0;fill-opacity:1"/></svg>