Skip to content Skip to sidebar Skip to footer

How To Change Emscripten Browser Input Method From Window.prompt To Something More Sensible?

I have a C++ function which once called consumes input from stdin. Exporting this function to javascript using emscripten causes calls to window.prompt. Interacting with browser p

Solution 1:

From what I understand you could try the following:

  1. Implement selecting a file in Javascript and access it via Javascript Blob interface.
  2. Allocate some memory in Emscripten

    var buf = Module._malloc( blob.size );
    
  3. Write the content of your Blob into the returned memory location from Javascript.

    Module.HEAPU8.set( new Uint8Array(blob), buf );
    
  4. Pass that memory location to a second Emscripten compiled function, which then processes the file content and

  5. Deallocate allocated memory.

    Module._free( buf );
    

Best to read the wiki first.

Solution 2:

A way would be to use the Emscripten Filesystem API, for example by calling FS.init in the Module preRun function, passing a custom function as the standard input.

var Module = {
  preRun: function() {
    functionstdin() {
      // Return ASCII code of character, or null if no input
    }

    var stdout = null; // Keep as defaultvar stderr = null;  // Keep as default
    FS.init(stdin, stdout, stderr);
  }
};

The function is quite low-level: is must deal with one character at a time. To read some data from a blob, you could do something like:

var data = newInt8Array([1,2,3,4,5]);
var blob = newBlob([array], {type: 'application/octet-binary'});
var reader = newFileReader();
var result;
reader.addEventListener("loadend", function() {
  result = newInt8Array(reader.result);
});
var i = 0;
varModule = {
  preRun: function() {
    functionstdin() {
      if (if < result.byteLength {
        var code = result[i];
        ++i;
        return code;
      } else {
        returnnull;
      }
    }

    var stdout = null; // Keep as defaultvar stderr = null; // Keep as defaultFS.init(stdin, stdout, stderr);
  }
};

Note (as you have hinted), due to the asynchronous nature of the reader, there could be a race condition: the reader must have loaded before you can expect the data at the standard input. You might need to implement some mechanism to avoid this in a real case. Depending on your exact requirements, you could make it so the Emscripten program doesn't actually call main() until you have the data:

var fileRead = false;
var initialised = false;
var result;

var array =  newInt8Array([1,2,3,4,5]);
var blob = newBlob([array], {type: 'application/octet-binary'});
var reader = newFileReader();
reader.addEventListener("loadend", function() {
   result = newInt8Array(reader.result);
   fileRead = true;
   runIfCan();
});
reader.readAsArrayBuffer(blob);

var i = 0;
varModule = {
   preRun: function() {
      functionstdin() {
         if (i < result.byteLength)
         {
            var code = result[i];
            ++i;
            return code;
         } else{
            returnnull;
         }
      }

      var stdout = null;
      var stderr = null;
      FS.init(stdin, stdout, stderr);
      initialised = true;
      runIfCan();
   },
   noInitialRun: true
};

functionrunIfCan() {
   if (fileRead && initialised) {
      // Module.run() doesn't seem to work hereModule.callMain();
   }
}

Note: this is a version of my answer at Providing stdin to an emscripten HTML program? , but with focus on the standard input, and adding parts about passing data from a Blob.

Post a Comment for "How To Change Emscripten Browser Input Method From Window.prompt To Something More Sensible?"