如何将 emscripten 浏览器输入法从 window.prompt 更改为更明智的方法?

Posted

技术标签:

【中文标题】如何将 emscripten 浏览器输入法从 window.prompt 更改为更明智的方法?【英文标题】:How to change emscripten browser input method from window.prompt to something more sensible? 【发布时间】:2013-04-12 20:48:19 【问题描述】:

我有一个 C++ 函数,它一旦被调用就会消耗来自标准输入的输入。使用 emscripten 将此函数导出到 javascript 会导致调用 window.prompt。

与浏览器提示交互确实是一项繁琐的任务。首先,您一次只能粘贴一行。其次,指示 EOF 的唯一方法是按“取消”。最后但并非最不重要的唯一方法(在我的函数的情况下)使其停止通过 window.prompt 要求用户输入是通过选中复选框以防止弹出更多提示。

对我来说,最好的输入法是阅读一些 blob。我知道我可以破解 library.js,但我发现了一些问题:

    读取 blob 是异步的。 要读取 blob,首先您必须打开一个文件,用户必须先选择。 我真的不知道如何阻止我的函数永远读取这个 blob - 没有像 window.prompt 这样的复选框,我不确定如果在 window.prompt 中没有发现 EOF 是否会阻止它案例(仅检查复选框有帮助)。

最好的解决方案是某种回调,但我希望从更有经验的用户那里得到一些提示。

【问题讨论】:

请说明您正在处理什么样的输入以及您的应用程序的总体思路是什么。 INCHI 库:iupac.org/home/publications/e-resources/inchi/download.html,对计算化学极为重要。输入是 molfile:en.wikipedia.org/wiki/Structure_data_file#Molfile 我正在尝试从命令行程序 inchi-1 中导出“process_single_input”方法,您可以在第一个链接的源代码中找到该方法。 您可以在这里查看我目前得到的信息:mnowotka.kei.pl/inchi 在 javascript 控制台中运行导出的函数类型:bla = Module.cwrap('process_single_input', 'string', 'string') \n bla('bla -STDIO') Molfile 的最大尺寸通常是多少? 不应该很大。我们可以放心地假设开始时不超过 100kB。 【参考方案1】:

据我了解,您可以尝试以下方法:

    在Javascript中实现选择文件并通过JavascriptBlob接口访问它。

    Emscripten

    中分配一些内存
    var buf = Module._malloc( blob.size );
    

    Blob 的内容写入 Javascript 返回的内存位置。

    Module.HEAPU8.set( new Uint8Array(blob), buf );
    

    将该内存位置传递给第二个 Emscripten 编译函数,该函数然后处理文件内容并

    释放分配的内存。

    Module._free( buf );
    

最好先阅读the wiki。

【讨论】:

第一点很简单。你有第 2 点和第 3 点的例子吗? 添加了一些来自 wiki 的示例。【参考方案2】:

一种方法是使用 Emscripten 文件系统 API,例如在 Module preRun 函数中调用 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();
   

注意:这是我在 Providing stdin to an emscripten HTML program? 的答案的一个版本,但重点是标准输入,并添加了有关从 Blob 传递数据的部分。

【讨论】:

您好,我应该在哪个文件中覆盖标准输入模块?

以上是关于如何将 emscripten 浏览器输入法从 window.prompt 更改为更明智的方法?的主要内容,如果未能解决你的问题,请参考以下文章

Emscripten:提供下载/保存生成的 MEMFS 文件

如何使用 Emscripten 将对象从 Javascript 传递到 C++

Emscripten 调用 SDL_Init 冻结浏览器文本输入

如何使用 Emscripten 将 Hello Word 从 Swift 编译为 JavaScript

是否可以使用 Emscripten 从 JavaScript 调用 C++ 函数?

如何直接从原生 JavaScript 前端与 Emscripten Web Worker 交互