unicode detect. docs. device attr. focus/blur. smacs checks.

This commit is contained in:
Christopher Jeffrey 2013-07-13 23:38:43 -05:00
parent 8aa718c280
commit ccf3794be2
3 changed files with 160 additions and 2 deletions

View File

@ -194,6 +194,9 @@ The screen on which every other node renders.
- **keypress** - received on key events. - **keypress** - received on key events.
- **element [name]** - global events received for all elements. - **element [name]** - global events received for all elements.
- **key [name]** - received on key event for [name]. - **key [name]** - received on key event for [name].
- **focus, blur** - when the terminal window focuses/blurs. requires a terminal
supporting the focus protocol and focus needs to be passed to
program.enableMouse().
##### Methods: ##### Methods:

View File

@ -50,6 +50,8 @@ function Program(options) {
this.terminal = options.terminal || process.env.TERM || 'xterm'; this.terminal = options.terminal || process.env.TERM || 'xterm';
this.unicode = this.detectUnicode();
// if (!Program.global) { // if (!Program.global) {
// Program._write = process.stdout.write; // Program._write = process.stdout.write;
// process.stdout.write = function() {}; // process.stdout.write = function() {};
@ -499,6 +501,110 @@ Program.prototype._bindResponse = function(s) {
} }
} }
// CSI P s c
// Send Device Attributes (Primary DA).
// CSI > P s c
// Send Device Attributes (Secondary DA).
if (parts = /^\x1b\[(\?|>)(\d*(?:;\d*)*)c/.exec(s)) {
var primary = parts[1] === '?'
, parts = parts[2].split(';').map(function(ch) { return +ch || 0; })
, out = {};
if (primary) {
out.type = 'primary-attribute';
// VT100-style params:
if (parts[0] === 1 && parts[2] === 2) {
out.term = 'vt100';
out.advancedVideo = true;
} else if (parts[0] === 1 && parts[2] === 0) {
out.term = 'vt101';
} else if (parts[0] === 6) {
out.term = 'vt102';
} else if (parts[0] === 60
&& parts[1] === 1 && parts[2] === 2
&& parts[3] === 6 && parts[4] === 8
&& parts[5] === 9 && parts[6] === 15) {
out.term = 'vt220';
} else {
// VT200-style params:
parts.forEach(function(attr) {
switch (attr) {
case 1:
out.132cols = true;
break;
case 2:
out.printer = true;
break;
case 6:
out.selectiveErase = true;
break;
case 8:
out.userDefinedKeys = true;
break;
case 9:
out.nationalReplacementCharsets = true;
break;
case 15:
out.technicalCharacters = true;
break;
case 18:
out.userWindows = true;
break;
case 21:
out.horizontalScrolling = true;
break;
case 22:
out.ansiColor = true;
break;
case 29:
out.ansiTextLocator = true;
break;
}
});
}
} else {
out.type = 'secondary-attribute';
switch (parts[0]) {
case 0:
out.term = 'vt100';
break;
case 1:
out.term = 'vt220';
break;
case 2:
out.term = 'vt240';
break;
case 18:
out.term = 'vt330';
break;
case 19:
out.term = 'vt340';
break;
case 24:
out.term = 'vt320';
break;
case 41:
out.term = 'vt420';
break;
case 61:
out.term = 'vt510';
break;
case 64:
out.term = 'vt520';
break;
case 65:
out.term = 'vt525';
break;
}
out.firmwareVersion = parts[1];
out.romCartridgeRegistrationNumber = parts[2];
}
return this.emit('response', {
deviceAttributes: out
});
}
// CSI Ps n Device Status Report (DSR). // CSI Ps n Device Status Report (DSR).
// Ps = 5 -> Status Report. Result (``OK'') is // Ps = 5 -> Status Report. Result (``OK'') is
// CSI 0 n // CSI 0 n
@ -673,6 +779,42 @@ Program.prototype._bindResponse = function(s) {
} }
}; };
// Not as foolproof as I'd like it to be.
Program.prototype.detectUnicode = function() {
var LANG = process.env.LANG
+ ':' + process.env.LANGUAGE
+ ':' + process.env.LC_ALL
+ ':' + process.env.LC_CTYPE;
return /utf-?8/i.test(LANG);
};
// Could do something goofy like this:
Program.prototype.detectUnicode_ = function(callback) {
var out = String.fromCharCode((0x1b << 8) | '['.charCodeAt(0)) + 'c'
, done;
this.once('response', function(data) {
if (done) return;
done = true;
if (data.deviceAttributes) {
return callback(null, false);
}
});
this.write(out);
this.cub(2);
this.write(' ');
this.cub(2);
setTimeout(function() {
if (done) return;
done = true;
return callback(null, true);
}, 100);
};
Program.prototype.receive = function(text, callback) { Program.prototype.receive = function(text, callback) {
var listeners = (this._events && this._events['keypress']) || [] var listeners = (this._events && this._events['keypress']) || []
, bak = listeners.slice() , bak = listeners.slice()

View File

@ -306,6 +306,14 @@ function Screen(options) {
self._resizeTimer = setTimeout(resize, time); self._resizeTimer = setTimeout(resize, time);
}); });
this.program.on('focus', function() {
self.emit('focus');
});
this.program.on('blur', function() {
self.emit('blur');
});
this.program.alternateBuffer(); this.program.alternateBuffer();
this.program.hideCursor(); this.program.hideCursor();
@ -758,8 +766,13 @@ Screen.prototype.draw = function(start, end) {
} }
} }
// TODO: Figure out a way to detect utf8 terminals. if (!this.program.unicode && this.tput
if (this.tput && this.tput.strings.enter_alt_charset_mode && SCLD[ch]) { && this.tput.strings.enter_alt_charset_mode && SCLD[ch]
&& this.tput.strings.enter_alt_charset_mode !== '\x1b[11m') {
// TODO: Possibly do not check for unicode above.
// For some reason TERM=linux has smacs/rmacs, but it maps to `^[[11m`
// and it does not switch to the DEC SCLD character set. What the hell?
// xterm: \x1b(0, screen: \x0e
ch = this.tput.smacs() + SCLD[ch] + this.tput.rmacs(); ch = this.tput.smacs() + SCLD[ch] + this.tput.rmacs();
} }