How to make xterm.js accept input?

corasan picture corasan · Jun 9, 2017 · Viewed 18.5k times · Source

I'm using xterm.js for a project but I can't get it to accept input. Whenever I try to type in the terminal nothing happens and there's no documentation or examples telling how to accomplish this.

This is what I have:

const term = new XTerm({
    cols: 100,
    cursorBlink: true,
    rows: 120
});
term.open(document.getElementById('terminal-window'), true)
term.fit()
term.writeln('Hello World!')

Answer

Mohamed Allal picture Mohamed Allal · Mar 16, 2018

xtermjs is a library that expose an api, that allow us to build fully xterm based terminal emulator. But for every of the terminal functionalities you need to implement it through the api. Using the event listeners. And handling them. And combining it with others packages depend on what you want to achieve.

For input here are ways of doing it:

term.on('key', (key, ev) => {
        console.log(key.charCodeAt(0));
        if (key.charCodeAt(0) == 13)
            term.write('\n');
        term.write(key);
});

Another example to see how you need to manipulate and how you can achieve things is :

term.textarea.onkeypress = function (e) {
        term.write(String.fromCharCode(e.keyCode));
}

here the link to the api, related to the terminal functionalities: https://xtermjs.org/docs/api/terminal/#onevent-callback`

you can for example clear the terminal using term.clear();

here an example that expose how the on data event work

term.on('data', (data) => {
        term.write(data);
   });

you will see that with that event, you can handle the data that is dispatched to the terminal. for instance when typing.

NOW sure this is all good. But that's not what gona help with a real app. To grasp better how things are i suggest the read of those articles and links:

to get you started right away! know that pty (pseudotty = pseudo terminal), here node-pty allow us to spawn a terminal process. and have an object that allow us to write to the terminal and so manipulate that terminal. then using xterm we will be able to write data to the pty and get data from the pty. (you can see it like this: the pty is the soul the real terminal that run. and xterm the body that allow us to expose that soul and so get to see.) both xterm and pty provide event on data. and it became as simple as that :

var os = require('os');
var pty = require('node-pty');
var Terminal = require('xterm').Terminal;

// Initialize node-pty with an appropriate shell
const shell = process.env[os.platform() === 'win32' ? 'COMSPEC' : 'SHELL'];
const ptyProcess = pty.spawn(shell, [], {
  name: 'xterm-color',
  cols: 80,
  rows: 30,
  cwd: process.cwd(),
  env: process.env
});

// Initialize xterm.js and attach it to the DOM
const xterm = new Terminal();
xterm.open(document.getElementById('xterm'));

// Setup communication between xterm.js and node-pty
xterm.on('data', (data) => {
  ptyProcess.write(data);
});
ptyProcess.on('data', function (data) {
  xterm.write(data);
});

see how the on data event are used. when something is wrote to ptyProcess. we write it in xterm. and when something is wrote on xterm we write it to the ptyProcess. note that this is for an electron application. so all is straight forward!

Now if what you are doing isn't withing electron and that is a browser to server terminal. where xterm will live in the client and the processing will run on the server. which in that case using node-pty mean we will be using nodejs. then we need something in plus. and that the websockets. the principle stay the same, but we will need to link xterm and the pty through the websocket. That's it the idea. the example above provided in the second link express that very well. the project is in two part, the backend and the front end, main.js refer to the front end and app.js to the backend, and xterm will be in the main.js and app.js contain node-pty. pay attention to all what is done in that demo. I suggest to go all through it, to test things yourself, and also to run that same demo, to see and compare between what you simply achieve and what is different with the demo.

Now third link, a good article, where the backend isn't nodejs. Plus may be there is more details because it's a tutorial and not just a demo. If not familiar with the back-end language here it's ok. that stay give a great idea on how you accomplish the work. Even though the first two links may suffice and more. after all are wrote by the one maintaining both projects.

For the websockets and the principles it's as follow: you set a socket communication between the client and the server. you init the pty in the server. and xterm in the client. then in the server when ever the pty get data, you push that data to the client, where you take it and write it to xterm. And as the same in the client whenever xterm get data you send it to the server, where you get the data and write it to the pty. now that's at the all simple things. there is more details to it. like handling the columns and rows and re-dimension. the demo from the second link show very well that. Hope that get you started, and that is helpful.

if you are adventurous, looking at some project where such terminal where implemented there is no better, even such projects can be more complicated. To site some, there is visual studio code => search the project for node-pty. you will find your road. but here is where you need to go to cut it out: src/vs/workbench/parts/terminal. there is hyper https://github.com/zeit/hyper. and here the list for more projects: https://github.com/xtermjs/xterm.js/#real-world-uses

you can also load one of the sites that implement a terminal or an ide and try and see how they implemented xterm in the server side. it can give you a great deal of insight. example : https://aws.amazon.com/cloud9/

why you may need to look at more projects, it's about the affinity, and how you configure xterm, apply all the add-ons, manipulate the font, and resizing, search. and different things. Good luck! happy coding!