Как изменить метод ввода браузера emscripten из window.prompt на что-то более разумное?

У меня есть функция C ++, которая когда-то вызывала потребляет ввод из стандартного ввода. Экспорт этой функции в javascript с использованием emscripten вызывает вызовы window.prompt.

Взаимодействие с подсказкой браузера — действительно утомительная задача. Прежде всего, вы можете вставить только одну строку за раз. Во-вторых, единственный способ указать EOF — нажать «Отмена». Последний, но не менее важный способ (в случае моей функции) заставить его перестать запрашивать ввод у пользователя через window.prompt — установить флажок, предотвращающий появление дополнительных запросов.

Для меня лучшим способом ввода было бы чтение какого-нибудь блоба. Я знаю, что могу взломать library.js, но вижу некоторые проблемы:

  1. Чтение BLOB-объектов является асинхронным.
  2. Чтобы прочитать блоб, сначала нужно открыть файл, который пользователь должен выбрать первым.
  3. Я действительно не знаю, как запретить моей функции читать этот BLOB-объект вечно — здесь нет флажка, как в случае с window.prompt, и я не уверен, остановит ли EOF остановку, если это не произошло в случае window.prompt (только помогла проверка флажка).

Лучшим решением будет какой-то обратный вызов, но я хотел бы увидеть подсказки от более опытных пользователей.

4

Решение

Из того, что я понимаю, вы можете попробовать следующее:

  1. Реализуйте выбор файла в Javascript и доступ к нему через Javascript Blob интерфейс.
  2. Выделите немного памяти в Emscripten

    var buf = Module._malloc( blob.size );
    
  3. Напишите содержание вашего Blob в возвращенную область памяти из Javascript.

    Module.HEAPU8.set( new Uint8Array(blob), buf );
    
  4. Передайте эту ячейку памяти второму Emscripten скомпилированная функция, которая затем обрабатывает содержимое файла и

  5. Освободить выделенную память.

    Module._free( buf );
    

Лучше всего читать вики первый.

1

Другие решения

Можно было бы использовать 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-объекта.

0

По вопросам рекламы [email protected]