From 0f76df23976f31de4d78556d41fdee71996ebd46 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Tue, 28 May 2019 12:59:29 +0200 Subject: [PATCH 1/3] Add OS clipboard set support to OS Javascript --- platform/javascript/os_javascript.cpp | 19 +++++++++++++++++++ platform/javascript/os_javascript.h | 2 ++ 2 files changed, 21 insertions(+) diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index c69e6f0cb83..20b7e9350fe 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -795,6 +795,25 @@ const char *OS_JavaScript::get_audio_driver_name(int p_driver) const { return "JavaScript"; } +// Clipboard +void OS_JavaScript::set_clipboard(const String &p_text) { + OS::set_clipboard(p_text); + /* clang-format off */ + int err = EM_ASM_INT({ + var text = UTF8ToString($0); + if (!navigator.clipboard || !navigator.clipboard.writeText) + return 1; + navigator.clipboard.writeText(text).catch(e => { + // Setting OS clipboard is only possible from an input callback. + console.error("Setting OS clipboard is only possible from an input callback for the HTML5 plafrom. Exception:", e); + }); + return 0; + }, p_text.utf8().get_data()); + /* clang-format on */ + ERR_EXPLAIN("Clipboard API is not supported."); + ERR_FAIL_COND(err); +} + // Lifecycle int OS_JavaScript::get_current_video_driver() const { return video_driver_index; diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index a0c7c31f2d7..7f9706b7116 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -133,6 +133,8 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void set_clipboard(const String &p_text); + virtual MainLoop *get_main_loop() const; void run_async(); bool main_loop_iterate(); From 2b436dd50e55e32bf09021d3c819339a7fce3e9f Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Tue, 28 May 2019 22:27:03 +0200 Subject: [PATCH 2/3] Kinda working HTML5 clipboard paste. Listen to paste events to update local clipboard. CTRL+V still not working out of the box. To do that, We would need to change how we handle keypress, most likely making it worse and less safe. In the end, I'm not sure we can fix it properly for now. Maybe in the future, with the Clipboard API, support of which is still pretty limited on chrome, and only available to extensions in Firefox. For now, you can paste via: - Browser bar -> Edit -> Paste. - Middle mouse click (Linux only, copies secondary clipboard). And THEN press CTRL+V --- platform/javascript/os_javascript.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 20b7e9350fe..6c4764bf7b2 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -796,6 +796,11 @@ const char *OS_JavaScript::get_audio_driver_name(int p_driver) const { } // Clipboard +extern "C" EMSCRIPTEN_KEEPALIVE void update_clipboard(const char *p_text) { + // Only call set_clipboard from OS (sets local clipboard) + OS::get_singleton()->OS::set_clipboard(p_text); +} + void OS_JavaScript::set_clipboard(const String &p_text) { OS::set_clipboard(p_text); /* clang-format off */ @@ -958,6 +963,11 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, (['mouseover', 'mouseleave', 'focus', 'blur']).forEach(function(event, index) { Module.canvas.addEventListener(event, send_notification.bind(null, notifications[index])); }); + // Clipboard + const update_clipboard = cwrap('update_clipboard', null, ['string']); + window.addEventListener('paste', function(evt) { + update_clipboard(evt.clipboardData.getData('text')); + }, true); }, MainLoop::NOTIFICATION_WM_MOUSE_ENTER, MainLoop::NOTIFICATION_WM_MOUSE_EXIT, From ce542bced1167a465ba2fc4150e16816e6d82e29 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Wed, 29 May 2019 21:30:29 +0200 Subject: [PATCH 3/3] Implement Clipboard API read when supported. Being async, the first time a value is pasted GUI elements will still return the previous one. This at least until 'clipboardchange' window event gets implemented by user agents. --- platform/javascript/os_javascript.cpp | 17 +++++++++++++++++ platform/javascript/os_javascript.h | 1 + 2 files changed, 18 insertions(+) diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index 6c4764bf7b2..502463a6f1f 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -819,6 +819,23 @@ void OS_JavaScript::set_clipboard(const String &p_text) { ERR_FAIL_COND(err); } +String OS_JavaScript::get_clipboard() const { + /* clang-format off */ + EM_ASM({ + try { + navigator.clipboard.readText().then(function (result) { + ccall('update_clipboard', 'void', ['string'], [result]); + }).catch(function (e) { + // Fail graciously. + }); + } catch (e) { + // Fail graciously. + } + }); + /* clang-format on */ + return this->OS::get_clipboard(); +} + // Lifecycle int OS_JavaScript::get_current_video_driver() const { return video_driver_index; diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 7f9706b7116..27b23a46733 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -134,6 +134,7 @@ public: virtual const char *get_audio_driver_name(int p_driver) const; virtual void set_clipboard(const String &p_text); + virtual String get_clipboard() const; virtual MainLoop *get_main_loop() const; void run_async();