У меня есть функция C ++, которая когда-то вызывала потребляет ввод из стандартного ввода. Экспорт этой функции в javascript с использованием emscripten вызывает вызовы window.prompt.
Взаимодействие с подсказкой браузера — действительно утомительная задача. Прежде всего, вы можете вставить только одну строку за раз. Во-вторых, единственный способ указать EOF — нажать «Отмена». Последний, но не менее важный способ (в случае моей функции) заставить его перестать запрашивать ввод у пользователя через window.prompt — установить флажок, предотвращающий появление дополнительных запросов.
Для меня лучшим способом ввода было бы чтение какого-нибудь блоба. Я знаю, что могу взломать library.js, но вижу некоторые проблемы:
Лучшим решением будет какой-то обратный вызов, но я хотел бы увидеть подсказки от более опытных пользователей.
Из того, что я понимаю, вы можете попробовать следующее:
Blob
интерфейс.Выделите немного памяти в Emscripten
var buf = Module._malloc( blob.size );
Напишите содержание вашего Blob
в возвращенную область памяти из Javascript.
Module.HEAPU8.set( new Uint8Array(blob), buf );
Передайте эту ячейку памяти второму Emscripten скомпилированная функция, которая затем обрабатывает содержимое файла и
Освободить выделенную память.
Module._free( buf );
Лучше всего читать вики первый.
Можно было бы использовать API файловой системы Emscripten, например, вызвав FS.init в функции предварительного запуска модуля, передавая пользовательскую функцию в качестве стандартного ввода.
var Module = {
preRun: function() {
function stdin() {
// Return ASCII code of character, or null if no input
}
var stdout = null; // Keep as default
var stderr = null; // Keep as default
FS.init(stdin, stdout, stderr);
}
};
Функция довольно низкого уровня: она должна иметь дело с одним символом за раз. Чтобы прочитать некоторые данные из BLOB-объекта, вы можете сделать что-то вроде:
var data = new Int8Array([1,2,3,4,5]);
var blob = new Blob([array], {type: 'application/octet-binary'});
var reader = new FileReader();
var result;
reader.addEventListener("loadend", function() {
result = new Int8Array(reader.result);
});
var i = 0;
var Module = {
preRun: function() {
function stdin() {
if (if < result.byteLength {
var code = result[i];
++i;
return code;
} else {
return null;
}
}
var stdout = null; // Keep as default
var stderr = null; // Keep as default
FS.init(stdin, stdout, stderr);
}
};
Обратите внимание (как вы намекали), из-за асинхронного характера считывателя может возникнуть условие гонки: считыватель должен быть загружен, прежде чем вы сможете ожидать данные на стандартном входе. Возможно, вам придется реализовать какой-то механизм, чтобы избежать этого в реальном случае. В зависимости от ваших точных требований, вы можете сделать так, чтобы программа Emscripten на самом деле не вызывала main()
пока у вас нет данных:
var fileRead = false;
var initialised = false;
var result;
var array = new Int8Array([1,2,3,4,5]);
var blob = new Blob([array], {type: 'application/octet-binary'});
var reader = new FileReader();
reader.addEventListener("loadend", function() {
result = new Int8Array(reader.result);
fileRead = true;
runIfCan();
});
reader.readAsArrayBuffer(blob);
var i = 0;
var Module = {
preRun: function() {
function stdin() {
if (i < result.byteLength)
{
var code = result[i];
++i;
return code;
} else{
return null;
}
}
var stdout = null;
var stderr = null;
FS.init(stdin, stdout, stderr);
initialised = true;
runIfCan();
},
noInitialRun: true
};
function runIfCan() {
if (fileRead && initialised) {
// Module.run() doesn't seem to work here
Module.callMain();
}
}
Примечание: это версия моего ответа на Предоставление стандартного ввода в HTML-программу emscripten? , но с акцентом на стандартный ввод и добавлением частей о передаче данных из BLOB-объекта.