diff options
Diffstat (limited to 'platform/javascript')
-rw-r--r-- | platform/javascript/audio_driver_javascript.cpp | 20 | ||||
-rw-r--r-- | platform/javascript/audio_driver_javascript.h | 7 | ||||
-rw-r--r-- | platform/javascript/display_server_javascript.cpp | 105 | ||||
-rw-r--r-- | platform/javascript/display_server_javascript.h | 20 | ||||
-rw-r--r-- | platform/javascript/dom_keys.inc | 587 | ||||
-rw-r--r-- | platform/javascript/javascript_main.cpp | 62 | ||||
-rw-r--r-- | platform/javascript/os_javascript.cpp | 25 | ||||
-rw-r--r-- | platform/javascript/os_javascript.h | 5 |
8 files changed, 352 insertions, 479 deletions
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index b8914414e6..9604914b2c 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -36,6 +36,15 @@ AudioDriverJavaScript *AudioDriverJavaScript::singleton = nullptr; +bool AudioDriverJavaScript::is_available() { + return EM_ASM_INT({ + if (!(window.AudioContext || window.webkitAudioContext)) { + return 0; + } + return 1; + }) != 0; +} + const char *AudioDriverJavaScript::get_name() const { return "JavaScript"; } @@ -207,12 +216,14 @@ void AudioDriverJavaScript::finish_async() { /* clang-format off */ EM_ASM({ - var ref = Module.IDHandler.get($0); + const id = $0; + var ref = Module.IDHandler.get(id); Module.async_finish.push(new Promise(function(accept, reject) { if (!ref) { - console.log("Ref not found!", $0, Module.IDHandler); + console.log("Ref not found!", id, Module.IDHandler); setTimeout(accept, 0); } else { + Module.IDHandler.remove(id); const context = ref['context']; // Disconnect script and input. ref['script'].disconnect(); @@ -226,7 +237,6 @@ void AudioDriverJavaScript::finish_async() { }); } })); - Module.IDHandler.remove($0); }, id); /* clang-format on */ } @@ -293,9 +303,5 @@ Error AudioDriverJavaScript::capture_stop() { } AudioDriverJavaScript::AudioDriverJavaScript() { - _driver_id = 0; - internal_buffer = nullptr; - buffer_length = 0; - singleton = this; } diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h index 9b26be001e..f029a91db0 100644 --- a/platform/javascript/audio_driver_javascript.h +++ b/platform/javascript/audio_driver_javascript.h @@ -34,12 +34,13 @@ #include "servers/audio_server.h" class AudioDriverJavaScript : public AudioDriver { - float *internal_buffer; + float *internal_buffer = nullptr; - int _driver_id; - int buffer_length; + int _driver_id = 0; + int buffer_length = 0; public: + static bool is_available(); void mix_to_js(); void process_capture(float sample); diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index b95674efc3..2f0a2faa83 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -44,18 +44,15 @@ #define DOM_BUTTON_XBUTTON1 3 #define DOM_BUTTON_XBUTTON2 4 +char DisplayServerJavaScript::canvas_id[256] = { 0 }; +static bool cursor_inside_canvas = true; + DisplayServerJavaScript *DisplayServerJavaScript::get_singleton() { return static_cast<DisplayServerJavaScript *>(DisplayServer::get_singleton()); } // Window (canvas) -extern "C" EMSCRIPTEN_KEEPALIVE void _set_canvas_id(uint8_t *p_data, int p_data_size) { - DisplayServerJavaScript *display = DisplayServerJavaScript::get_singleton(); - display->canvas_id.parse_utf8((const char *)p_data, p_data_size); - display->canvas_id = "#" + display->canvas_id; -} - -static void focus_canvas() { +void DisplayServerJavaScript::focus_canvas() { /* clang-format off */ EM_ASM( Module['canvas'].focus(); @@ -63,7 +60,7 @@ static void focus_canvas() { /* clang-format on */ } -static bool is_canvas_focused() { +bool DisplayServerJavaScript::is_canvas_focused() { /* clang-format off */ return EM_ASM_INT_V( return document.activeElement == Module['canvas']; @@ -71,8 +68,21 @@ static bool is_canvas_focused() { /* clang-format on */ } -static Point2 compute_position_in_canvas(int x, int y) { - DisplayServerJavaScript *display = DisplayServerJavaScript::get_singleton(); +bool DisplayServerJavaScript::check_size_force_redraw() { + int canvas_width; + int canvas_height; + emscripten_get_canvas_element_size(DisplayServerJavaScript::canvas_id, &canvas_width, &canvas_height); + if (last_width != canvas_width || last_height != canvas_height) { + last_width = canvas_width; + last_height = canvas_height; + // Update the framebuffer size and for redraw. + emscripten_set_canvas_element_size(DisplayServerJavaScript::canvas_id, canvas_width, canvas_height); + return true; + } + return false; +} + +Point2 DisplayServerJavaScript::compute_position_in_canvas(int p_x, int p_y) { int canvas_x = EM_ASM_INT({ return Module['canvas'].getBoundingClientRect().x; }); @@ -81,23 +91,22 @@ static Point2 compute_position_in_canvas(int x, int y) { }); int canvas_width; int canvas_height; - emscripten_get_canvas_element_size(display->canvas_id.utf8().get_data(), &canvas_width, &canvas_height); + emscripten_get_canvas_element_size(canvas_id, &canvas_width, &canvas_height); double element_width; double element_height; - emscripten_get_element_css_size(display->canvas_id.utf8().get_data(), &element_width, &element_height); + emscripten_get_element_css_size(canvas_id, &element_width, &element_height); - return Point2((int)(canvas_width / element_width * (x - canvas_x)), - (int)(canvas_height / element_height * (y - canvas_y))); + return Point2((int)(canvas_width / element_width * (p_x - canvas_x)), + (int)(canvas_height / element_height * (p_y - canvas_y))); } -static bool cursor_inside_canvas = true; - EM_BOOL DisplayServerJavaScript::fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data) { DisplayServerJavaScript *display = get_singleton(); // Empty ID is canvas. String target_id = String::utf8(p_event->id); - if (target_id.empty() || "#" + target_id == display->canvas_id) { + String canvas_str_id = String::utf8(canvas_id); + if (target_id.empty() || target_id == canvas_str_id) { // This event property is the only reliable data on // browser fullscreen state. if (p_event->isFullscreen) { @@ -131,20 +140,20 @@ extern "C" EMSCRIPTEN_KEEPALIVE void _drop_files_callback(char *p_filev[], int p // Keys template <typename T> -static void dom2godot_mod(T *emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event) { +void DisplayServerJavaScript::dom2godot_mod(T *emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event) { godot_event->set_shift(emscripten_event_ptr->shiftKey); godot_event->set_alt(emscripten_event_ptr->altKey); godot_event->set_control(emscripten_event_ptr->ctrlKey); godot_event->set_metakey(emscripten_event_ptr->metaKey); } -static Ref<InputEventKey> setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) { +Ref<InputEventKey> DisplayServerJavaScript::setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) { Ref<InputEventKey> ev; ev.instance(); ev->set_echo(emscripten_event->repeat); dom2godot_mod(emscripten_event, ev); - ev->set_keycode(dom2godot_keycode(emscripten_event->keyCode)); - ev->set_physical_keycode(dom2godot_keycode(emscripten_event->keyCode)); + ev->set_keycode(dom_code2godot_scancode(emscripten_event->code, emscripten_event->key, false)); + ev->set_physical_keycode(dom_code2godot_scancode(emscripten_event->code, emscripten_event->key, true)); String unicode = String::utf8(emscripten_event->key); // Check if empty or multi-character (e.g. `CapsLock`). @@ -289,7 +298,7 @@ EM_BOOL DisplayServerJavaScript::mousemove_callback(int p_event_type, const Emsc } // Cursor -static const char *godot2dom_cursor(DisplayServer::CursorShape p_shape) { +const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape p_shape) { switch (p_shape) { case DisplayServer::CURSOR_ARROW: return "auto"; @@ -330,7 +339,7 @@ static const char *godot2dom_cursor(DisplayServer::CursorShape p_shape) { } } -static void set_css_cursor(const char *p_cursor) { +void DisplayServerJavaScript::set_css_cursor(const char *p_cursor) { /* clang-format off */ EM_ASM_({ Module['canvas'].style.cursor = UTF8ToString($0); @@ -338,7 +347,7 @@ static void set_css_cursor(const char *p_cursor) { /* clang-format on */ } -static bool is_css_cursor_hidden() { +bool DisplayServerJavaScript::is_css_cursor_hidden() const { /* clang-format off */ return EM_ASM_INT({ return Module['canvas'].style.cursor === 'none'; @@ -820,23 +829,6 @@ DisplayServer *DisplayServerJavaScript::create_func(const String &p_rendering_dr } DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - /* clang-format off */ - EM_ASM({ - const canvas = Module['canvas']; - var enc = new TextEncoder("utf-8"); - var buffer = new Uint8Array(enc.encode(canvas.id)); - var len = buffer.byteLength; - var out = _malloc(len); - HEAPU8.set(buffer, out); - ccall("_set_canvas_id", - "void", - ["number", "number"], - [out, len] - ); - _free(out); - }); - /* clang-format on */ - RasterizerDummy::make_current(); // TODO GLES2 in Godot 4.0... or webgpu? #if 0 EmscriptenWebGLContextAttributes attributes; @@ -859,7 +851,7 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive gl_initialization_error = true; } - EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(canvas_id.utf8().get_data(), &attributes); + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(canvas_id, &attributes); if (emscripten_webgl_make_context_current(ctx) != EMSCRIPTEN_RESULT_SUCCESS) { gl_initialization_error = true; } @@ -881,7 +873,6 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive } EMSCRIPTEN_RESULT result; - CharString id = canvas_id.utf8(); #define EM_CHECK(ev) \ if (result != EMSCRIPTEN_RESULT_SUCCESS) \ ERR_PRINT("Error while setting " #ev " callback: Code " + itos(result)); @@ -895,16 +886,16 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive // JavaScript APIs. For APIs that are not (sufficiently) exposed, EM_ASM // is used below. SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, mousemove, mousemove_callback) - SET_EM_CALLBACK(id.get_data(), mousedown, mouse_button_callback) + SET_EM_CALLBACK(canvas_id, mousedown, mouse_button_callback) SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, mouseup, mouse_button_callback) - SET_EM_CALLBACK(id.get_data(), wheel, wheel_callback) - SET_EM_CALLBACK(id.get_data(), touchstart, touch_press_callback) - SET_EM_CALLBACK(id.get_data(), touchmove, touchmove_callback) - SET_EM_CALLBACK(id.get_data(), touchend, touch_press_callback) - SET_EM_CALLBACK(id.get_data(), touchcancel, touch_press_callback) - SET_EM_CALLBACK(id.get_data(), keydown, keydown_callback) - SET_EM_CALLBACK(id.get_data(), keypress, keypress_callback) - SET_EM_CALLBACK(id.get_data(), keyup, keyup_callback) + SET_EM_CALLBACK(canvas_id, wheel, wheel_callback) + SET_EM_CALLBACK(canvas_id, touchstart, touch_press_callback) + SET_EM_CALLBACK(canvas_id, touchmove, touchmove_callback) + SET_EM_CALLBACK(canvas_id, touchend, touch_press_callback) + SET_EM_CALLBACK(canvas_id, touchcancel, touch_press_callback) + SET_EM_CALLBACK(canvas_id, keydown, keydown_callback) + SET_EM_CALLBACK(canvas_id, keypress, keypress_callback) + SET_EM_CALLBACK(canvas_id, keyup, keyup_callback) SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, fullscreenchange, fullscreen_change_callback) SET_EM_CALLBACK_NOTARGET(gamepadconnected, gamepad_change_callback) SET_EM_CALLBACK_NOTARGET(gamepaddisconnected, gamepad_change_callback) @@ -1012,7 +1003,7 @@ Size2i DisplayServerJavaScript::screen_get_size(int p_screen) const { Rect2i DisplayServerJavaScript::screen_get_usable_rect(int p_screen) const { int canvas[2]; - emscripten_get_canvas_element_size(canvas_id.utf8().get_data(), canvas, canvas + 1); + emscripten_get_canvas_element_size(canvas_id, canvas, canvas + 1); return Rect2i(0, 0, canvas[0], canvas[1]); } @@ -1103,12 +1094,14 @@ Size2i DisplayServerJavaScript::window_get_min_size(WindowID p_window) const { } void DisplayServerJavaScript::window_set_size(const Size2i p_size, WindowID p_window) { - emscripten_set_canvas_element_size(canvas_id.utf8().get_data(), p_size.x, p_size.y); + last_width = p_size.x; + last_height = p_size.y; + emscripten_set_canvas_element_size(canvas_id, p_size.x, p_size.y); } Size2i DisplayServerJavaScript::window_get_size(WindowID p_window) const { int canvas[2]; - emscripten_get_canvas_element_size(canvas_id.utf8().get_data(), canvas, canvas + 1); + emscripten_get_canvas_element_size(canvas_id, canvas, canvas + 1); return Size2(canvas[0], canvas[1]); } @@ -1134,7 +1127,7 @@ void DisplayServerJavaScript::window_set_mode(WindowMode p_mode, WindowID p_wind strategy.canvasResolutionScaleMode = EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF; strategy.filteringMode = EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT; strategy.canvasResizedCallback = nullptr; - EMSCRIPTEN_RESULT result = emscripten_request_fullscreen_strategy(canvas_id.utf8().get_data(), false, &strategy); + EMSCRIPTEN_RESULT result = emscripten_request_fullscreen_strategy(canvas_id, false, &strategy); ERR_FAIL_COND_MSG(result == EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED, "Enabling fullscreen is only possible from an input callback for the HTML5 platform."); ERR_FAIL_COND_MSG(result != EMSCRIPTEN_RESULT_SUCCESS, "Enabling fullscreen is only possible from an input callback for the HTML5 platform."); } break; diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h index 9860ecdf98..b149665d67 100644 --- a/platform/javascript/display_server_javascript.h +++ b/platform/javascript/display_server_javascript.h @@ -53,6 +53,21 @@ class DisplayServerJavaScript : public DisplayServer { double last_click_ms = 0; int last_click_button_index = -1; + int last_width = 0; + int last_height = 0; + + // utilities + static Point2 compute_position_in_canvas(int p_x, int p_y); + static void focus_canvas(); + static bool is_canvas_focused(); + template <typename T> + static void dom2godot_mod(T *emscripten_event_ptr, Ref<InputEventWithModifiers> godot_event); + static Ref<InputEventKey> setup_key_event(const EmscriptenKeyboardEvent *emscripten_event); + static const char *godot2dom_cursor(DisplayServer::CursorShape p_shape); + static void set_css_cursor(const char *p_cursor); + bool is_css_cursor_hidden() const; + + // events static EM_BOOL fullscreen_change_callback(int p_event_type, const EmscriptenFullscreenChangeEvent *p_event, void *p_user_data); static EM_BOOL keydown_callback(int p_event_type, const EmscriptenKeyboardEvent *p_event, void *p_user_data); @@ -81,17 +96,20 @@ protected: public: // Override return type to make writing static callbacks less tedious. static DisplayServerJavaScript *get_singleton(); + static char canvas_id[256]; WindowMode window_mode = WINDOW_MODE_WINDOWED; String clipboard; - String canvas_id; Callable window_event_callback; Callable input_event_callback; Callable input_text_callback; Callable drop_files_callback; + // utilities + bool check_size_force_redraw(); + // from DisplayServer virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual bool has_feature(Feature p_feature) const; diff --git a/platform/javascript/dom_keys.inc b/platform/javascript/dom_keys.inc index 882e943471..e3f2ce42b4 100644 --- a/platform/javascript/dom_keys.inc +++ b/platform/javascript/dom_keys.inc @@ -30,400 +30,203 @@ #include "core/os/keyboard.h" -// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Constants_for_keyCode_value -#define DOM_VK_CANCEL 0x03 -#define DOM_VK_HELP 0x06 -#define DOM_VK_BACK_SPACE 0x08 -#define DOM_VK_TAB 0x09 -#define DOM_VK_CLEAR 0x0C -#define DOM_VK_RETURN 0x0D -#define DOM_VK_ENTER 0x0E // "Reserved, but not used." -#define DOM_VK_SHIFT 0x10 -#define DOM_VK_CONTROL 0x11 -#define DOM_VK_ALT 0x12 -#define DOM_VK_PAUSE 0x13 -#define DOM_VK_CAPS_LOCK 0x14 -#define DOM_VK_KANA 0x15 -#define DOM_VK_HANGUL 0x15 -#define DOM_VK_EISU 0x16 -#define DOM_VK_JUNJA 0x17 -#define DOM_VK_FINAL 0x18 -#define DOM_VK_HANJA 0x19 -#define DOM_VK_KANJI 0x19 -#define DOM_VK_ESCAPE 0x1B -#define DOM_VK_CONVERT 0x1C -#define DOM_VK_NONCONVERT 0x1D -#define DOM_VK_ACCEPT 0x1E -#define DOM_VK_MODECHANGE 0x1F -#define DOM_VK_SPACE 0x20 -#define DOM_VK_PAGE_UP 0x21 -#define DOM_VK_PAGE_DOWN 0x22 -#define DOM_VK_END 0x23 -#define DOM_VK_HOME 0x24 -#define DOM_VK_LEFT 0x25 -#define DOM_VK_UP 0x26 -#define DOM_VK_RIGHT 0x27 -#define DOM_VK_DOWN 0x28 -#define DOM_VK_SELECT 0x29 -#define DOM_VK_PRINT 0x2A -#define DOM_VK_EXECUTE 0x2B -#define DOM_VK_PRINTSCREEN 0x2C -#define DOM_VK_INSERT 0x2D -#define DOM_VK_DELETE 0x2E -#define DOM_VK_0 0x30 -#define DOM_VK_1 0x31 -#define DOM_VK_2 0x32 -#define DOM_VK_3 0x33 -#define DOM_VK_4 0x34 -#define DOM_VK_5 0x35 -#define DOM_VK_6 0x36 -#define DOM_VK_7 0x37 -#define DOM_VK_8 0x38 -#define DOM_VK_9 0x39 -#define DOM_VK_COLON 0x3A -#define DOM_VK_SEMICOLON 0x3B -#define DOM_VK_LESS_THAN 0x3C -#define DOM_VK_EQUALS 0x3D -#define DOM_VK_GREATER_THAN 0x3E -#define DOM_VK_QUESTION_MARK 0x3F -#define DOM_VK_AT 0x40 -#define DOM_VK_A 0x41 -#define DOM_VK_B 0x42 -#define DOM_VK_C 0x43 -#define DOM_VK_D 0x44 -#define DOM_VK_E 0x45 -#define DOM_VK_F 0x46 -#define DOM_VK_G 0x47 -#define DOM_VK_H 0x48 -#define DOM_VK_I 0x49 -#define DOM_VK_J 0x4A -#define DOM_VK_K 0x4B -#define DOM_VK_L 0x4C -#define DOM_VK_M 0x4D -#define DOM_VK_N 0x4E -#define DOM_VK_O 0x4F -#define DOM_VK_P 0x50 -#define DOM_VK_Q 0x51 -#define DOM_VK_R 0x52 -#define DOM_VK_S 0x53 -#define DOM_VK_T 0x54 -#define DOM_VK_U 0x55 -#define DOM_VK_V 0x56 -#define DOM_VK_W 0x57 -#define DOM_VK_X 0x58 -#define DOM_VK_Y 0x59 -#define DOM_VK_Z 0x5A -#define DOM_VK_WIN 0x5B -#define DOM_VK_CONTEXT_MENU 0x5D -#define DOM_VK_SLEEP 0x5F -#define DOM_VK_NUMPAD0 0x60 -#define DOM_VK_NUMPAD1 0x61 -#define DOM_VK_NUMPAD2 0x62 -#define DOM_VK_NUMPAD3 0x63 -#define DOM_VK_NUMPAD4 0x64 -#define DOM_VK_NUMPAD5 0x65 -#define DOM_VK_NUMPAD6 0x66 -#define DOM_VK_NUMPAD7 0x67 -#define DOM_VK_NUMPAD8 0x68 -#define DOM_VK_NUMPAD9 0x69 -#define DOM_VK_MULTIPLY 0x6A -#define DOM_VK_ADD 0x6B -#define DOM_VK_SEPARATOR 0x6C -#define DOM_VK_SUBTRACT 0x6D -#define DOM_VK_DECIMAL 0x6E -#define DOM_VK_DIVIDE 0x6F -#define DOM_VK_F1 0x70 -#define DOM_VK_F2 0x71 -#define DOM_VK_F3 0x72 -#define DOM_VK_F4 0x73 -#define DOM_VK_F5 0x74 -#define DOM_VK_F6 0x75 -#define DOM_VK_F7 0x76 -#define DOM_VK_F8 0x77 -#define DOM_VK_F9 0x78 -#define DOM_VK_F10 0x79 -#define DOM_VK_F11 0x7A -#define DOM_VK_F12 0x7B -#define DOM_VK_F13 0x7C -#define DOM_VK_F14 0x7D -#define DOM_VK_F15 0x7E -#define DOM_VK_F16 0x7F -#define DOM_VK_F17 0x80 -#define DOM_VK_F18 0x81 -#define DOM_VK_F19 0x82 -#define DOM_VK_F20 0x83 -#define DOM_VK_F21 0x84 -#define DOM_VK_F22 0x85 -#define DOM_VK_F23 0x86 -#define DOM_VK_F24 0x87 -#define DOM_VK_NUM_LOCK 0x90 -#define DOM_VK_SCROLL_LOCK 0x91 -#define DOM_VK_WIN_OEM_FJ_JISHO 0x92 -#define DOM_VK_WIN_OEM_FJ_MASSHOU 0x93 -#define DOM_VK_WIN_OEM_FJ_TOUROKU 0x94 -#define DOM_VK_WIN_OEM_FJ_LOYA 0x95 -#define DOM_VK_WIN_OEM_FJ_ROYA 0x96 -#define DOM_VK_CIRCUMFLEX 0xA0 -#define DOM_VK_EXCLAMATION 0xA1 -#define DOM_VK_DOUBLE_QUOTE 0xA2 -#define DOM_VK_HASH 0xA3 -#define DOM_VK_DOLLAR 0xA4 -#define DOM_VK_PERCENT 0xA5 -#define DOM_VK_AMPERSAND 0xA6 -#define DOM_VK_UNDERSCORE 0xA7 -#define DOM_VK_OPEN_PAREN 0xA8 -#define DOM_VK_CLOSE_PAREN 0xA9 -#define DOM_VK_ASTERISK 0xAA -#define DOM_VK_PLUS 0xAB -#define DOM_VK_PIPE 0xAC -#define DOM_VK_HYPHEN_MINUS 0xAD -#define DOM_VK_OPEN_CURLY_BRACKET 0xAE -#define DOM_VK_CLOSE_CURLY_BRACKET 0xAF -#define DOM_VK_TILDE 0xB0 -#define DOM_VK_VOLUME_MUTE 0xB5 -#define DOM_VK_VOLUME_DOWN 0xB6 -#define DOM_VK_VOLUME_UP 0xB7 -#define DOM_VK_COMMA 0xBC -#define DOM_VK_PERIOD 0xBE -#define DOM_VK_SLASH 0xBF -#define DOM_VK_BACK_QUOTE 0xC0 -#define DOM_VK_OPEN_BRACKET 0xDB -#define DOM_VK_BACK_SLASH 0xDC -#define DOM_VK_CLOSE_BRACKET 0xDD -#define DOM_VK_QUOTE 0xDE -#define DOM_VK_META 0xE0 -#define DOM_VK_ALTGR 0xE1 -#define DOM_VK_WIN_ICO_HELP 0xE3 -#define DOM_VK_WIN_ICO_00 0xE4 -#define DOM_VK_WIN_ICO_CLEAR 0xE6 -#define DOM_VK_WIN_OEM_RESET 0xE9 -#define DOM_VK_WIN_OEM_JUMP 0xEA -#define DOM_VK_WIN_OEM_PA1 0xEB -#define DOM_VK_WIN_OEM_PA2 0xEC -#define DOM_VK_WIN_OEM_PA3 0xED -#define DOM_VK_WIN_OEM_WSCTRL 0xEE -#define DOM_VK_WIN_OEM_CUSEL 0xEF -#define DOM_VK_WIN_OEM_ATTN 0xF0 -#define DOM_VK_WIN_OEM_FINISH 0xF1 -#define DOM_VK_WIN_OEM_COPY 0xF2 -#define DOM_VK_WIN_OEM_AUTO 0xF3 -#define DOM_VK_WIN_OEM_ENLW 0xF4 -#define DOM_VK_WIN_OEM_BACKTAB 0xF5 -#define DOM_VK_ATTN 0xF6 -#define DOM_VK_CRSEL 0xF7 -#define DOM_VK_EXSEL 0xF8 -#define DOM_VK_EREOF 0xF9 -#define DOM_VK_PLAY 0xFA -#define DOM_VK_ZOOM 0xFB -#define DOM_VK_PA1 0xFD -#define DOM_VK_WIN_OEM_CLEAR 0xFE - -int dom2godot_keycode(int dom_keycode) { - if (DOM_VK_0 <= dom_keycode && dom_keycode <= DOM_VK_Z) { - // ASCII intersection - return dom_keycode; - } - - if (DOM_VK_NUMPAD0 <= dom_keycode && dom_keycode <= DOM_VK_NUMPAD9) { - // Numpad numbers - return KEY_KP_0 + (dom_keycode - DOM_VK_NUMPAD0); +// See https://w3c.github.io/uievents-code/#code-value-tables +int dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], bool p_physical) { +#define DOM2GODOT(p_str, p_godot_code) \ + if (memcmp((const void *)p_str, (void *)p_code, strlen(p_str) + 1) == 0) { \ + return KEY_##p_godot_code; \ } - if (DOM_VK_F1 <= dom_keycode && dom_keycode <= DOM_VK_F16) { - // F1-F16 - return KEY_F1 + (dom_keycode - DOM_VK_F1); + // Numpad section. + DOM2GODOT("NumLock", NUMLOCK); + DOM2GODOT("Numpad0", KP_0); + DOM2GODOT("Numpad1", KP_1); + DOM2GODOT("Numpad2", KP_2); + DOM2GODOT("Numpad3", KP_3); + DOM2GODOT("Numpad4", KP_4); + DOM2GODOT("Numpad5", KP_5); + DOM2GODOT("Numpad6", KP_6); + DOM2GODOT("Numpad7", KP_7); + DOM2GODOT("Numpad8", KP_8); + DOM2GODOT("Numpad9", KP_9); + DOM2GODOT("NumpadAdd", KP_ADD); + DOM2GODOT("NumpadBackspace", BACKSPACE); + DOM2GODOT("NumpadClear", CLEAR); + DOM2GODOT("NumpadClearEntry", CLEAR); + //DOM2GODOT("NumpadComma", UNKNOWN); + DOM2GODOT("NumpadDecimal", KP_PERIOD); + DOM2GODOT("NumpadDivide", KP_DIVIDE); + DOM2GODOT("NumpadEnter", KP_ENTER); + DOM2GODOT("NumpadEqual", EQUAL); + //DOM2GODOT("NumpadHash", UNKNOWN); + //DOM2GODOT("NumpadMemoryAdd", UNKNOWN); + //DOM2GODOT("NumpadMemoryClear", UNKNOWN); + //DOM2GODOT("NumpadMemoryRecall", UNKNOWN); + //DOM2GODOT("NumpadMemoryStore", UNKNOWN); + //DOM2GODOT("NumpadMemorySubtract", UNKNOWN); + DOM2GODOT("NumpadMultiply", KP_MULTIPLY); + DOM2GODOT("NumpadParenLeft", PARENLEFT); + DOM2GODOT("NumpadParenRight", PARENRIGHT); + DOM2GODOT("NumpadStar", KP_MULTIPLY); // or ASTERISK ? + DOM2GODOT("NumpadSubtract", KP_SUBTRACT); + + // Printable ASCII. + if (!p_physical) { + uint8_t b0 = (uint8_t)p_key[0]; + uint8_t b1 = (uint8_t)p_key[1]; + uint8_t b2 = (uint8_t)p_key[2]; + if (b1 == 0 && b0 > 0x1F && b0 < 0x7F) { // ASCII. + if (b0 > 0x60 && b0 < 0x7B) { // Lowercase ASCII. + b0 -= 32; + } + return b0; + } + +#define _U_2BYTES_MASK 0xE0 +#define _U_2BYTES 0xC0 + // Latin-1 codes. + if (b2 == 0 && (b0 & _U_2BYTES_MASK) == _U_2BYTES) { // 2-bytes utf8, only known latin. + uint32_t key = ((b0 & ~_U_2BYTES_MASK) << 6) | (b1 & 0x3F); + if (key >= 0xA0 && key <= 0xDF) { + return key; + } + if (key >= 0xE0 && key <= 0xFF) { // Lowercase known latin. + key -= 0x20; + return key; + } + } +#undef _U_2BYTES_MASK +#undef _U_2BYTES } - switch (dom_keycode) { - //case DOM_VK_CANCEL: return KEY_UNKNOWN; - case DOM_VK_HELP: - return KEY_HELP; - case DOM_VK_BACK_SPACE: - return KEY_BACKSPACE; - case DOM_VK_TAB: - return KEY_TAB; - - case DOM_VK_CLEAR: - case DOM_VK_WIN_OEM_CLEAR: // OEM duplicate - return KEY_CLEAR; - - case DOM_VK_RETURN: - case DOM_VK_ENTER: // unused according to MDN - return KEY_ENTER; - - case DOM_VK_SHIFT: - return KEY_SHIFT; - case DOM_VK_CONTROL: - return KEY_CONTROL; - - case DOM_VK_ALT: - case DOM_VK_ALTGR: - return KEY_ALT; - - case DOM_VK_PAUSE: - return KEY_PAUSE; - case DOM_VK_CAPS_LOCK: - return KEY_CAPSLOCK; - - /* - case DOM_VK_KANA: return KEY_UNKNOWN; - case DOM_VK_HANGUL: return KEY_UNKNOWN; - case DOM_VK_EISU: return KEY_UNKNOWN; - case DOM_VK_JUNJA: return KEY_UNKNOWN; - case DOM_VK_FINAL: return KEY_UNKNOWN; - case DOM_VK_HANJA: return KEY_UNKNOWN; - case DOM_VK_KANJI: return KEY_UNKNOWN; - */ - - case DOM_VK_ESCAPE: - return KEY_ESCAPE; - /* - case DOM_VK_CONVERT: return KEY_UNKNOWN; - case DOM_VK_NONCONVERT: return KEY_UNKNOWN; - case DOM_VK_ACCEPT: return KEY_UNKNOWN; - case DOM_VK_MODECHANGE: return KEY_UNKNOWN; - */ - - case DOM_VK_SPACE: - return KEY_SPACE; - case DOM_VK_PAGE_UP: - return KEY_PAGEUP; - case DOM_VK_PAGE_DOWN: - return KEY_PAGEDOWN; - case DOM_VK_END: - return KEY_END; - case DOM_VK_HOME: - return KEY_HOME; - case DOM_VK_LEFT: - return KEY_LEFT; - case DOM_VK_UP: - return KEY_UP; - case DOM_VK_RIGHT: - return KEY_RIGHT; - case DOM_VK_DOWN: - return KEY_DOWN; - - //case DOM_VK_SELECT: return KEY_UNKNOWN; - - case DOM_VK_PRINTSCREEN: - case DOM_VK_PRINT: - return KEY_PRINT; - - //case DOM_VK_EXECUTE: return KEY_UNKNOWN; - case DOM_VK_INSERT: - return KEY_INSERT; - case DOM_VK_DELETE: - return KEY_DELETE; - - case DOM_VK_META: - case DOM_VK_WIN: - return KEY_META; - - case DOM_VK_CONTEXT_MENU: - return KEY_MENU; - case DOM_VK_SLEEP: - return KEY_STANDBY; - - // Numpad keys - case DOM_VK_MULTIPLY: - return KEY_KP_MULTIPLY; - case DOM_VK_ADD: - return KEY_KP_ADD; - case DOM_VK_SEPARATOR: - return KEY_KP_PERIOD; // Good enough? - case DOM_VK_SUBTRACT: - return KEY_KP_SUBTRACT; - case DOM_VK_DECIMAL: - return KEY_KP_PERIOD; - case DOM_VK_DIVIDE: - return KEY_KP_DIVIDE; - - /* - case DOM_VK_F17: return KEY_UNKNOWN; - case DOM_VK_F18: return KEY_UNKNOWN; - case DOM_VK_F19: return KEY_UNKNOWN; - case DOM_VK_F20: return KEY_UNKNOWN; - case DOM_VK_F21: return KEY_UNKNOWN; - case DOM_VK_F22: return KEY_UNKNOWN; - case DOM_VK_F23: return KEY_UNKNOWN; - case DOM_VK_F24: return KEY_UNKNOWN; - */ - - case DOM_VK_NUM_LOCK: - return KEY_NUMLOCK; - case DOM_VK_SCROLL_LOCK: - return KEY_SCROLLLOCK; - - /* - case DOM_VK_WIN_OEM_FJ_JISHO: return KEY_UNKNOWN; - case DOM_VK_WIN_OEM_FJ_MASSHOU: return KEY_UNKNOWN; - case DOM_VK_WIN_OEM_FJ_TOUROKU: return KEY_UNKNOWN; - case DOM_VK_WIN_OEM_FJ_LOYA: return KEY_UNKNOWN; - case DOM_VK_WIN_OEM_FJ_ROYA: return KEY_UNKNOWN; - */ - - case DOM_VK_CIRCUMFLEX: - return KEY_ASCIICIRCUM; - case DOM_VK_EXCLAMATION: - return KEY_EXCLAM; - case DOM_VK_DOUBLE_QUOTE: - return KEY_QUOTEDBL; - case DOM_VK_HASH: - return KEY_NUMBERSIGN; - case DOM_VK_DOLLAR: - return KEY_DOLLAR; - case DOM_VK_PERCENT: - return KEY_PERCENT; - case DOM_VK_AMPERSAND: - return KEY_AMPERSAND; - case DOM_VK_UNDERSCORE: - return KEY_UNDERSCORE; - case DOM_VK_OPEN_PAREN: - return KEY_PARENLEFT; - case DOM_VK_CLOSE_PAREN: - return KEY_PARENRIGHT; - case DOM_VK_ASTERISK: - return KEY_ASTERISK; - case DOM_VK_PLUS: - return KEY_PLUS; - case DOM_VK_PIPE: - return KEY_BAR; - case DOM_VK_HYPHEN_MINUS: - return KEY_MINUS; - case DOM_VK_OPEN_CURLY_BRACKET: - return KEY_BRACELEFT; - case DOM_VK_CLOSE_CURLY_BRACKET: - return KEY_BRACERIGHT; - case DOM_VK_TILDE: - return KEY_ASCIITILDE; - - case DOM_VK_VOLUME_MUTE: - return KEY_VOLUMEMUTE; - case DOM_VK_VOLUME_DOWN: - return KEY_VOLUMEDOWN; - case DOM_VK_VOLUME_UP: - return KEY_VOLUMEUP; - - case DOM_VK_COMMA: - return KEY_COMMA; - case DOM_VK_PERIOD: - return KEY_PERIOD; - case DOM_VK_SLASH: - return KEY_SLASH; - case DOM_VK_BACK_QUOTE: - return KEY_QUOTELEFT; - case DOM_VK_OPEN_BRACKET: - return KEY_BRACKETLEFT; - case DOM_VK_BACK_SLASH: - return KEY_BACKSLASH; - case DOM_VK_CLOSE_BRACKET: - return KEY_BRACKETRIGHT; - case DOM_VK_QUOTE: - return KEY_APOSTROPHE; - - // The rest is OEM/unusual. - - default: - return KEY_UNKNOWN; - }; + // Alphanumeric section. + DOM2GODOT("Backquote", QUOTELEFT); + DOM2GODOT("Backslash", BACKSLASH); + DOM2GODOT("BracketLeft", BRACKETLEFT); + DOM2GODOT("BracketRight", BRACKETRIGHT); + DOM2GODOT("Comma", COMMA); + DOM2GODOT("Digit0", 0); + DOM2GODOT("Digit1", 1); + DOM2GODOT("Digit2", 2); + DOM2GODOT("Digit3", 3); + DOM2GODOT("Digit4", 4); + DOM2GODOT("Digit5", 5); + DOM2GODOT("Digit6", 6); + DOM2GODOT("Digit7", 7); + DOM2GODOT("Digit8", 8); + DOM2GODOT("Digit9", 9); + DOM2GODOT("Equal", EQUAL); + DOM2GODOT("IntlBackslash", BACKSLASH); + //DOM2GODOT("IntlRo", UNKNOWN); + DOM2GODOT("IntlYen", YEN); + + DOM2GODOT("KeyA", A); + DOM2GODOT("KeyB", B); + DOM2GODOT("KeyC", C); + DOM2GODOT("KeyD", D); + DOM2GODOT("KeyE", E); + DOM2GODOT("KeyF", F); + DOM2GODOT("KeyG", G); + DOM2GODOT("KeyH", H); + DOM2GODOT("KeyI", I); + DOM2GODOT("KeyJ", J); + DOM2GODOT("KeyK", K); + DOM2GODOT("KeyL", L); + DOM2GODOT("KeyM", M); + DOM2GODOT("KeyN", N); + DOM2GODOT("KeyO", O); + DOM2GODOT("KeyP", P); + DOM2GODOT("KeyQ", Q); + DOM2GODOT("KeyR", R); + DOM2GODOT("KeyS", S); + DOM2GODOT("KeyT", T); + DOM2GODOT("KeyU", U); + DOM2GODOT("KeyV", V); + DOM2GODOT("KeyW", W); + DOM2GODOT("KeyX", X); + DOM2GODOT("KeyY", Y); + DOM2GODOT("KeyZ", Z); + + DOM2GODOT("Minus", MINUS); + DOM2GODOT("Period", PERIOD); + DOM2GODOT("Quote", APOSTROPHE); + DOM2GODOT("Semicolon", SEMICOLON); + DOM2GODOT("Slash", SLASH); + + // Functional keys in the Alphanumeric section. + DOM2GODOT("AltLeft", ALT); + DOM2GODOT("AltRight", ALT); + DOM2GODOT("Backspace", BACKSPACE); + DOM2GODOT("CapsLock", CAPSLOCK); + DOM2GODOT("ContextMenu", MENU); + DOM2GODOT("ControlLeft", CONTROL); + DOM2GODOT("ControlRight", CONTROL); + DOM2GODOT("Enter", ENTER); + DOM2GODOT("MetaLeft", SUPER_L); + DOM2GODOT("MetaRight", SUPER_R); + DOM2GODOT("ShiftLeft", SHIFT); + DOM2GODOT("ShiftRight", SHIFT); + DOM2GODOT("Space", SPACE); + DOM2GODOT("Tab", TAB); + + // ControlPad section. + DOM2GODOT("Delete", DELETE); + DOM2GODOT("End", END); + DOM2GODOT("Help", HELP); + DOM2GODOT("Home", HOME); + DOM2GODOT("Insert", INSERT); + DOM2GODOT("PageDown", PAGEDOWN); + DOM2GODOT("PageUp", PAGEUP); + + // ArrowPad section. + DOM2GODOT("ArrowDown", DOWN); + DOM2GODOT("ArrowLeft", LEFT); + DOM2GODOT("ArrowRight", RIGHT); + DOM2GODOT("ArrowUp", UP); + + // Function section. + DOM2GODOT("Escape", ESCAPE); + DOM2GODOT("F1", F1); + DOM2GODOT("F2", F2); + DOM2GODOT("F3", F3); + DOM2GODOT("F4", F4); + DOM2GODOT("F5", F5); + DOM2GODOT("F6", F6); + DOM2GODOT("F7", F7); + DOM2GODOT("F8", F8); + DOM2GODOT("F9", F9); + DOM2GODOT("F10", F10); + DOM2GODOT("F11", F11); + DOM2GODOT("F12", F12); + //DOM2GODOT("Fn", UNKNOWN); // never actually fired, but included in the standard draft. + //DOM2GODOT("FnLock", UNKNOWN); + DOM2GODOT("PrintScreen", PRINT); + DOM2GODOT("ScrollLock", SCROLLLOCK); + DOM2GODOT("Pause", PAUSE); + + // Media keys section. + DOM2GODOT("BrowserBack", BACK); + DOM2GODOT("BrowserFavorites", FAVORITES); + DOM2GODOT("BrowserForward", FORWARD); + DOM2GODOT("BrowserHome", OPENURL); + DOM2GODOT("BrowserRefresh", REFRESH); + DOM2GODOT("BrowserSearch", SEARCH); + DOM2GODOT("BrowserStop", STOP); + //DOM2GODOT("Eject", UNKNOWN); + DOM2GODOT("LaunchApp1", LAUNCH0); + DOM2GODOT("LaunchApp2", LAUNCH1); + DOM2GODOT("LaunchMail", LAUNCHMAIL); + DOM2GODOT("MediaPlayPause", MEDIAPLAY); + DOM2GODOT("MediaSelect", LAUNCHMEDIA); + DOM2GODOT("MediaStop", MEDIASTOP); + DOM2GODOT("MediaTrackNext", MEDIANEXT); + DOM2GODOT("MediaTrackPrevious", MEDIAPREVIOUS); + //DOM2GODOT("Power", UNKNOWN); + //DOM2GODOT("Sleep", UNKNOWN); + DOM2GODOT("AudioVolumeDown", VOLUMEDOWN); + DOM2GODOT("AudioVolumeMute", VOLUMEMUTE); + DOM2GODOT("AudioVolumeUp", VOLUMEUP); + //DOM2GODOT("WakeUp", UNKNOWN); + return KEY_UNKNOWN; +#undef DOM2GODOT } diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp index 740a72fafa..99672745e7 100644 --- a/platform/javascript/javascript_main.cpp +++ b/platform/javascript/javascript_main.cpp @@ -30,11 +30,13 @@ #include "core/io/resource_loader.h" #include "main/main.h" -#include "os_javascript.h" +#include "platform/javascript/display_server_javascript.h" +#include "platform/javascript/os_javascript.h" #include <emscripten/emscripten.h> static OS_JavaScript *os = nullptr; +static uint64_t target_ticks = 0; void exit_callback() { emscripten_cancel_main_loop(); // After this, we can exit! @@ -46,12 +48,32 @@ void exit_callback() { } void main_loop_callback() { + uint64_t current_ticks = os->get_ticks_usec(); + + bool force_draw = DisplayServerJavaScript::get_singleton()->check_size_force_redraw(); + if (force_draw) { + Main::force_redraw(); + } else if (current_ticks < target_ticks) { + return; // Skip frame. + } + + int target_fps = Engine::get_singleton()->get_target_fps(); + if (target_fps > 0) { + target_ticks += (uint64_t)(1000000 / target_fps); + } if (os->main_loop_iterate()) { emscripten_cancel_main_loop(); // Cancel current loop and wait for finalize_async. + /* clang-format off */ EM_ASM({ // This will contain the list of operations that need to complete before cleanup. - Module.async_finish = []; + Module.async_finish = [ + // Always contains at least one async promise, to avoid firing immediately if nothing is added. + new Promise(function(accept, reject) { + setTimeout(accept, 0); + }) + ]; }); + /* clang-format on */ os->get_main_loop()->finish(); os->finalize_async(); // Will add all the async finish functions. EM_ASM({ @@ -79,10 +101,35 @@ extern "C" EMSCRIPTEN_KEEPALIVE void main_after_fs_sync(char *p_idbfs_err) { ResourceLoader::set_abort_on_missing_resources(false); Main::start(); os->get_main_loop()->init(); + // Immediately run the first iteration. + // We are inside an animation frame, we want to immediately draw on the newly setup canvas. + main_loop_callback(); emscripten_resume_main_loop(); } int main(int argc, char *argv[]) { + // Create and mount userfs immediately. + EM_ASM({ + FS.mkdir('/userfs'); + FS.mount(IDBFS, {}, '/userfs'); + }); + + // Configure locale. + char locale_ptr[16]; + /* clang-format off */ + EM_ASM({ + stringToUTF8(Module['locale'], $0, 16); + }, locale_ptr); + /* clang-format on */ + setenv("LANG", locale_ptr, true); + + // Ensure the canvas ID. + /* clang-format off */ + EM_ASM({ + stringToUTF8("#" + Module['canvas'].id, $0, 255); + }, DisplayServerJavaScript::canvas_id); + /* clang-format on */ + os = new OS_JavaScript(); Main::setup(argv[0], argc - 1, &argv[1], false); emscripten_set_main_loop(main_loop_callback, -1, false); @@ -91,14 +138,13 @@ int main(int argc, char *argv[]) { // Sync from persistent state into memory and then // run the 'main_after_fs_sync' function. /* clang-format off */ - EM_ASM( - FS.mkdir('/userfs'); - FS.mount(IDBFS, {}, '/userfs'); + EM_ASM({ FS.syncfs(true, function(err) { - ccall('main_after_fs_sync', null, ['string'], [err ? err.message : ""]) + requestAnimationFrame(function() { + ccall('main_after_fs_sync', null, ['string'], [err ? err.message : ""]); + }); }); - - ); + }); /* clang-format on */ return 0; diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index ad4b5a5afa..1ff4304bcf 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -74,18 +74,12 @@ void OS_JavaScript::initialize() { EngineDebugger::register_uri_handler("ws://", RemoteDebuggerPeerWebSocket::create); EngineDebugger::register_uri_handler("wss://", RemoteDebuggerPeerWebSocket::create); #endif - - char locale_ptr[16]; - /* clang-format off */ - EM_ASM({ - stringToUTF8(Module['locale'], $0, 16); - }, locale_ptr); - /* clang-format on */ - setenv("LANG", locale_ptr, true); } void OS_JavaScript::resume_audio() { - audio_driver_javascript.resume(); + if (audio_driver_javascript) { + audio_driver_javascript->resume(); + } } void OS_JavaScript::set_main_loop(MainLoop *p_main_loop) { @@ -133,11 +127,17 @@ void OS_JavaScript::delete_main_loop() { void OS_JavaScript::finalize_async() { finalizing = true; - audio_driver_javascript.finish_async(); + if (audio_driver_javascript) { + audio_driver_javascript->finish_async(); + } } void OS_JavaScript::finalize() { delete_main_loop(); + if (audio_driver_javascript) { + memdelete(audio_driver_javascript); + audio_driver_javascript = nullptr; + } } // Miscellaneous @@ -246,7 +246,10 @@ void OS_JavaScript::initialize_joypads() { } OS_JavaScript::OS_JavaScript() { - AudioDriverManager::add_driver(&audio_driver_javascript); + if (AudioDriverJavaScript::is_available()) { + audio_driver_javascript = memnew(AudioDriverJavaScript); + AudioDriverManager::add_driver(audio_driver_javascript); + } Vector<Logger *> loggers; loggers.push_back(memnew(StdLogger)); diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index f0f18b44f8..22234f9355 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -40,7 +40,7 @@ class OS_JavaScript : public OS_Unix { MainLoop *main_loop = nullptr; - AudioDriverJavaScript audio_driver_javascript; + AudioDriverJavaScript *audio_driver_javascript = nullptr; bool finalizing = false; bool idb_available = false; @@ -83,6 +83,9 @@ public: String get_executable_path() const; virtual Error shell_open(String p_uri); virtual String get_name() const; + // Override default OS implementation which would block the main thread with delay_usec. + // Implemented in javascript_main.cpp loop callback instead. + virtual void add_frame_delay(bool p_can_draw) {} virtual bool can_draw() const; virtual String get_cache_path() const; |