[ion/clipboard] Add support for web simulator

Wrote methods for accessing the system clipboard from the web
simulator, as the methods in SDL_Clipboard do not work when the video
device uses emscripten.

Change-Id: Ib2e66530a6b013eca0cf69fb52372e9e3a21c8bb
This commit is contained in:
Gabriel Ozouf
2020-09-17 11:34:23 +02:00
committed by Émilie Feral
parent b9c34ace3a
commit 010b474f77
10 changed files with 105 additions and 1 deletions

View File

@@ -77,6 +77,7 @@ _closure_call \
_do_load \
_do_load_from_lexer \
_emscripten_sleep \
_emscripten_sleep_with_yield \
_fun_bc_call \
_fun_builtin_1_call \
_fun_builtin_var_call \
@@ -103,6 +104,14 @@ _mp_execute_bytecode \
_mp_hal_input \
_mp_import_name \
_mp_parse_compile_execute \
_get_clipboard_text \
__ZN3Ion9Clipboard4readEPcm \
__ZN9Clipboard10storedTextEv \
__ZN11LayoutField18privateHandleEventEN3Ion6Events5EventE \
__ZN11LayoutField11handleEventEN3Ion6Events5EventE \
__ZN8TextArea18privateHandleEventEN3Ion6Events5EventE \
__ZN8TextArea11handleEventEN3Ion6Events5EventE \
__ZN15ExpressionField11handleEventEN3Ion6Events5EventE \
_msleep
EMTERPRETIFY_WHITELIST = $(foreach sym,$(EMSCRIPTEN_ASYNC_SYMBOLS),"$(sym)",)END

View File

@@ -8,7 +8,6 @@ ion_src += $(addprefix ion/src/simulator/shared/, \
dummy/serial_number.cpp \
dummy/stack.cpp \
dummy/usb.cpp \
clipboard.cpp \
console_stdio.cpp:-consoledisplay \
crc32.cpp \
display.cpp:-headless \

View File

@@ -6,6 +6,7 @@ ion_src += $(addprefix ion/src/simulator/android/src/cpp/, \
ion_src += $(addprefix ion/src/simulator/shared/, \
dummy/callback.cpp \
dummy/language.cpp \
clipboard.cpp \
haptics.cpp \
)

View File

@@ -6,6 +6,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \
apple/language.m \
dummy/callback.cpp \
dummy/haptics_enabled.cpp \
clipboard.cpp \
haptics.cpp \
)

View File

@@ -16,6 +16,7 @@ ion_src += $(addprefix ion/src/simulator/linux/, \
ion_src += $(addprefix ion/src/simulator/shared/, \
dummy/callback.cpp \
dummy/haptics_enabled.cpp \
clipboard.cpp \
collect_registers_x86_64.s \
collect_registers.cpp \
haptics.cpp \

View File

@@ -6,6 +6,7 @@ ion_src += $(addprefix ion/src/simulator/shared/, \
apple/language.m \
dummy/callback.cpp \
dummy/haptics_enabled.cpp \
clipboard.cpp \
collect_registers_x86_64.s \
collect_registers.cpp \
haptics.cpp \

View File

@@ -2,6 +2,9 @@
#include <SDL.h>
#include <string.h>
/* This file implements the methods to access the system clipboard on all
* targets but the web simulator. */
namespace Ion {
void Clipboard::write(const char * text) {

View File

@@ -15,6 +15,7 @@ LDFLAGS += --pre-js ion/src/simulator/web/preamble_env.js
ion_src += $(addprefix ion/src/simulator/web/, \
callback.cpp \
clipboard.cpp \
helpers.cpp \
)

View File

@@ -0,0 +1,87 @@
#include <ion/clipboard.h>
#include <emscripten.h>
#include <SDL.h>
#include <assert.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
enum class AsyncStatus : uint32_t {
Pending,
Success,
Failure
};
/* When using emscripten, the SDL_Clipboard methods do not interact with the
* system clipboard, but only with an internal buffer. We thus need to
* implement our own methods via the JavaScript API.
* However, we still call the SDL_Clipboard methods as a fallback to preserve
* the copy-paste feature in case of calls to set_clipboard_text and
* get_clipboard_text failing. */
EM_JS(void, set_clipboard_text, (const char * text, AsyncStatus * status, AsyncStatus failure, AsyncStatus success), {
try {
navigator.clipboard.writeText(UTF8ToString(text)).then(
function () { HEAP32[status>>2] = success; },
function () { HEAP32[status>>2] = failure; }
);
} catch (error) {
console.error(error);
HEAP32[status>>2] = failure;
}
});
EM_JS(void, get_clipboard_text, (char * buffer, uint32_t bufferSize, AsyncStatus * status, AsyncStatus failure, AsyncStatus success), {
try {
navigator.clipboard.readText().then(
function(text) {
var lenghtBytes = Math.min(lengthBytesUTF8(text) + 1, bufferSize);
stringToUTF8(text, buffer, lenghtBytes);
HEAP32[status>>2] = success;
},
function(text) { HEAP32[status>>2] = failure; }
);
} catch (error) {
console.error(error);
HEAP32[status>>2] = failure;
}
});
namespace Ion {
void Clipboard::write(const char * text) {
/* FIXME : Handle the error if need be. */
/* As the rest of the execution does not depend on the system clipboard being
* properly filled at this point, the call to set_clipboard_text does not
* need to be made synchronous. */
AsyncStatus lock;
set_clipboard_text(text, &lock, AsyncStatus::Failure, AsyncStatus::Success);
/* Store a local copy of the text in case the browser does not grant access
* to the clipboard. */
SDL_SetClipboardText(text);
}
void Clipboard::read(char * buffer, size_t bufferSize) {
AsyncStatus lock = AsyncStatus::Pending;
static_assert(sizeof(size_t) <= sizeof(uint32_t), "Cast from size_t to uint32_t may overflow.");
get_clipboard_text(buffer, static_cast<uint32_t>(bufferSize), &lock, AsyncStatus::Failure, AsyncStatus::Success);
while (lock == AsyncStatus::Pending) {
emscripten_sleep_with_yield(10);
}
if (lock == AsyncStatus::Success) {
return;
}
/* If the browser does not grant access to the clipboard, read from a local
* copy to at least maintain the basic copy-paste functionnality. */
if (!SDL_HasClipboardText()) {
buffer[0] = '\0';
return;
}
char * text = SDL_GetClipboardText();
if (text) {
strlcpy(buffer, text, bufferSize);
SDL_free(text);
}
}
}

View File

@@ -7,6 +7,7 @@ ion_src += $(addprefix ion/src/simulator/windows/, \
ion_src += $(addprefix ion/src/simulator/shared/, \
dummy/callback.cpp \
dummy/haptics_enabled.cpp \
clipboard.cpp \
haptics.cpp \
)