scandum / tintin

TinTin++, aka tt++, is an extensible console MUD client.
https://tintin.mudhalla.net
GNU General Public License v3.0
204 stars 56 forks source link

pty question / wasm #190

Closed kjvalencik closed 11 months ago

kjvalencik commented 1 year ago

Hello! First, I'd like to say thanks for tintin, I've been using it for years and it's top notch software.

I've been working getting tt++ running in the browser with WebAssembly. It's actually going pretty smoothly. I needed to compile static versions of zlib and pcre, but after that I was able to build successfully with emscripten.

I'm using xterm.js and xterm-pty as the terminal emulator to get things running, with some glue code connecting TCP to websocker proxy (Rust) and a virtual filesystem. It's working well, ansi colors and all!

One issue I haven't been able to figure out is that input control sequences (e.g. up/down arrows) are being echoed by the PTY instead of being handled by tintin. I would expect to be able to scroll through history like on desktop.

I can read C well enough, but I've never been a C developer and would appreciate any pointers you have for where the problem might be.

Thanks! By the way, I'm happy to contribute the build back to the project if that's something you are interested in.

scandum commented 1 year ago

Hiyas, sounds cool. Have you checked out WebTin? https://github.com/scandum/webtin

You should be able to bind a-typical up and down sequences with a macro, or define them in tables.c in the cursor_table[] table.

Or is the problem more systematic? If it's just a few keys, I might be able to add them to the defaults.

If you publish your work on github I'd be happy to link to it from the link page on the website.

kjvalencik commented 1 year ago

I did see WebTin! Looks neat. I was hoping to do something purely on web to better support multiple users.

It might be more systematic because no control sequences are being handled.

Is Tintin expecting the raw keycodes instead of control sequences? Does Tintin not need a PTY?

Thanks!

scandum commented 1 year ago

Tintin is expecting the raw key codes in the input stream.

I don't have a firm understanding of PTYs, tintin just does what most console applications do.

kjvalencik commented 1 year ago

tl;dr -- I figured it out. Feel free to ignore the rest of this comment.


Thanks so much for helping. I see now that tintin is flipping a bunch of terminal flags off in terminal.c.

Changing the integration a bit, I've got up/down close to working. If I hit Up, Enter, it will execute the previous command. However, it doesn't write the command to the terminal after hitting Up. However, if I hit up a few more times, it will eventually write the command. However, when I hit enter on it, it's not that command.

It's almost like two different lists are being used. One to draw previous command and one to execute and the one that's used to draw has a bunch of empty lines in it.

Thanks again for the help!

Edit: If I go up a few and then start using the down arrow, the down arrow works as expected. I noticed in the code, cursor_down unconditionally redraws, while up doesn't. Maybe that's related?

Edit 2: Also, noticing left/right cursor position isn't lining up. I'll keep digging.

Edit 3: With the left/right cursor, it seems like the view is always one keystroke behind. For example:

  1. Type L - Nothing
  2. Type L - Move Left
  3. Type R - Move Left (executing 2)
  4. Type R - Move Right (executing 3)

Edit 4: I figured out that the reason the view wasn't updating was because the command wasn't actually executing until I queued up another read. I figured this out because clicking out of the terminal (sending a \e[O control sequence) as triggering it. If send this sequence after every read, it fixes the problem, but that doesn't seem right. I'd love to know if you have any insight here, but at least I'm unblocked.

Edit 5: I figured out my problem. My implementation of ___syscall__newselect was buggy. It was assuming that my buffer would be flushed all at once. However, tintin is only reading one character at a time. This means select would start marking things as not ready, even when there was data waiting to be read in emscripten's internal buffer. This is why sending a control character fixed it (really any character fixes it, but control character was a noop). Fixing my select implementation resolved the problem.

kjvalencik commented 1 year ago

@scandum I needed a few patches to get things working. Would you be willing to merge a few emscripten specific #ifdef to avoid needing to maintain them independently?

I'll open a PR when I get a chance, but in the meantime, a summary of the changes:

Cheers!

scandum commented 1 year ago

That shouldn't be a problem if it doesn't get too weird.

scandum commented 11 months ago

I don't think I ever saw that PR? I'll close this for now, let me know how things went. :)