I/O questions

139 views
Skip to first unread message

Stefan Meier

unread,
Feb 6, 2014, 11:14:10 AM2/6/14
to emscripte...@googlegroups.com
Hi,

first of all I want to apologize if this is not the right group for my questions, but I didn't find a more appropriate one. Recently I started my very first steps with emscripten - which btw is almost too cool to be really existing .-)

What I intended to do is porting an interpreter for text adventures written in C (called Magnetic, available under GPL). The interpreter is written in C und uses only stdio for input and output. There is no SDL version and considering the "nature" of the tool, SDL would be a lot overhead with gaining nothing, probably.

While I managed to get the emscripten version to do its output to plain html after a while I am now completely stuck when trying to get the user input working. Before I throw everything into the garbage can, perhaps someone with better JS skills than I have (and that's not a major challenge), can take a look at the following parts and confirm my current assumption: not solvable - or better, give me some hints what can be done.

The main loop of the interpreter is as simple as this:
running = 1;
while (running) running=ms_rungame();

The interpreter core is actually some kind of very reduced 68k emulator and each call to the ms_rungame "executes" one instruction. Now, when the interpreter is running, at some point it runs to a function called ms_flush for doing the output. I was able to gain from the various samples in the emsdk a way to get the output written to plain html with something like this:
sprintf(outBuffer, "reformatAndSet('%c','textout')",buffer[j]);
emscripten_run_script(outBuffer);
in the C code and this in the JS code:
    function reformatAndSet(text, target) {
       text = text.replace(/&/g, "&");
       text = text.replace(/</g, "&lt;");
       text = text.replace(/>/g, "&gt;");
       text = text.replace('\n', '<br>', 'g');
       document.getElementById(target).innerHTML += text;
    }

Most probably not a nice solution, but at least it works. But then I reach my showstopper. So when contuing at some point the interpreter calls a function named ms_getchar, which does fill an internal buffer array with the user input in a loop of getchar calls and then return the chars after after the other in subsequent calls to the ms_getchar routine. In the C version this function waits for the user input. Emscripten replaces the getchar calls with window.prompt calls, which actually do work, but from the point of the user experience are no real option. So, the problem is: Is it possible to keep the ms_getchar busy or blocked until the user has done his input (without locking up the browser). I tried a lot of different approaches, but never came close to a solution and as far as I understand JS can not be blocked or kept busy with threads, so it seems I am lost here?!?.
My last try was something like this, but this didn't work, either, most probably because I got wrong what the emscripten_start_main_loop and emscripten_stop_main_loop calls do. I also found a reference to a function emcripten_push_Main_loop_blocker, but couldn't find a sample how to use it. Another thought was if it might be possible to run the interpreter loop in a web worker, but I guess I will run into problems with filling my html then?

Last try (partly reconstructed, tried such much with the source that I messed it up at some point). Please bear with me if that is pure nonsense, I am not very familiar with JS, especially not with the parts beyond simple web pages.
in the HTML:
<form onsubmit="setInternalBuffer();return false;"><input type="text" size="50" maxlength="255" id="textin"></form>
and
function setInternalBuffer() {
       var userinput = document.getElementById('textin').value;
       var cstyle_ptr  = allocate(intArrayFromString(userinput), 'i8', ALLOC_NORMAL);
       transferbuffer = Module.cwrap('transferbuffer', 'void', ['string']);
       transferbuffer(cstyle_ptr);
       emscripten_start_main_loop();
      
    }
in the C code:
void transferbuffer(char * input)
{
   strcpy(inbuf,input);
}
and
char ms_getchar()
{
     int c=0;
     emscripten_pause_main_loop();
      if ((c = inbuf[inpos]) == '\n' || !c)
      {
          inpos = 0;
          memset(inbuf,0x00,256);
          c=0;
      }
     return (char)c;
}

I guess, the transferbuffer call in the JS function is not executed because the main loop is stopped?!?

Any chance to get this working or is it as simple as this not being suitable for JS?

Many, many thanks for listening and your help. If you want to mess around with the stuff yourself, please let me know and I'll make it available, it's open source anyway.

Stefan Meier

Jukka Jylänki

unread,
Feb 6, 2014, 11:56:03 AM2/6/14
to emscripte...@googlegroups.com
One option for blocking keyboard input you could try is to register a keyboard event callback e.g. via the emscripten library_html5.h handlers, and having ms_getchar() pause the main loop like you now do, and when you do get a key press, call resume on the main loop. Alternatively, if you don't want to keep pausing and resuming the main loop, you could just track a boolean that avoids the execution of any instructions in your interpreter while the key event query is pending. Unfortunately real blocking input is not possible without a dialog box.

You will need to break up the code that calls ms_getchar() to immediately return out of the event handler, and have the rest of the original code after ms_getchar() to be executed only after the keyboard event is received.

   Jukka




2014-02-06 Stefan Meier <stefanm...@gmail.com>:

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Stefan Meier

unread,
Feb 6, 2014, 2:51:04 PM2/6/14
to emscripte...@googlegroups.com
Thanks a lot for getting back at me. I think the second option is almost impossible to realize. The interpreter acts like a small 68k emulator. The call to ms_getchar ist triggered while an opcode is executed. If I would stall the emulation to wait for a boolean, I think I would end up in a loop thank would require a sleep command that I do not have or it woild block everything. I tried this, but to no achievments. Concerning the first option: How would this be different from the variant with the "submit intercept"? Wouldn't the problem persist that I cannot pass the user input data to the interpreter until the main loop has resumed?!?

Sorry if these are dumb questions. A lot new things to learn for me! (and Thanks again for replying!) 


2014-02-06 Stefan Meier <stefanm...@gmail.com>:
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Stefan Meier

unread,
Feb 6, 2014, 3:33:51 PM2/6/14
to emscripte...@googlegroups.com


just had another thought. Is it perhaps possible to write directly to memory? I think the problem with this code:

       var cstyle_ptr  = allocate(intArrayFromString(userinput), 'i8', ALLOC_NORMAL);
       transferbuffer = Module.cwrap('transferbuffer', 'void', ['string']);
       transferbuffer(cstyle_ptr);
       emscripten_start_main_loop();
is that transferbuffer is not executed because the main loop has stopped, however if I could "inject" the userinput directly into the memory and then resume the main loop, perhaps this could work?



Am Donnerstag, 6. Februar 2014 17:56:03 UTC+1 schrieb jj:


2014-02-06 Stefan Meier <stefanm...@gmail.com>:
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Jukka Jylänki

unread,
Feb 6, 2014, 10:53:01 PM2/6/14
to emscripte...@googlegroups.com
Functions wrapped with cwrap and ccall should execute independent of whether there is a main loop running or not. Also, it is possible to directly write to and read from memory by using the {{{ heapSetValue }}} and {{{ heapGetValue }}} mechanisms if you are implementing a --js-library file, and from other .js files, by directly accessing the global HEAPU32 etc. arrays. See the existing src/library_xx.js files with examples of who those set and get values are being used, they should cover the most of it.


2014-02-06 Stefan Meier <stefanm...@gmail.com>:
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

Stefan Meier

unread,
Feb 7, 2014, 4:23:33 PM2/7/14
to emscripte...@googlegroups.com
Hi,
now I am really confused. This would mean that my solution should actually work, doesn't it (when calling emscripten_resume_main_loop before transferbuffer(cstyle_ptr);)? However it seems that the emscripten_pause_main_loop doesn't have any effect at all. It progresses without pausing and still the call to transferbuffer doesn't get executed, although there is neither a compilation error nor any error in the Browser console. Seems, I am even more stuck than I thought...


2014-02-06 Stefan Meier <stefanm...@gmail.com>:


2014-02-06 Stefan Meier <stefanm...@gmail.com>:

To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
Reply all
Reply to author
Forward
0 new messages