+2010-09-04 Markus Gutschke <markus@shellinabox.com>
+
+ * Added an optional on-screen keyboard. Must be activated by the
+ user by selecting the option in the context-menu.
+
2010-09-03 Markus Gutschke <markus@shellinabox.com>
* Fix some scaling related issues. This fix is thanks to some
demo/demo.jspp \
demo/demo.xml \
demo/enabled.gif \
+ demo/keyboard.png \
demo/styles.css \
demo/print-styles.css \
demo/vt100.js \
shellinabox/print-styles.css \
shellinabox/enabled.gif \
shellinabox/favicon.ico \
+ shellinabox/keyboard.png \
+ shellinabox/keyboard-layout.html \
shellinabox/beep.wav \
config.h
shellinaboxd_LDADD = liblogging.la \
${top_srcdir}/demo/demo.js: ${top_srcdir}/demo/beep.wav \
${top_srcdir}/demo/demo.jspp \
+ ${top_srcdir}/demo/enabled.gif \
${top_srcdir}/demo/favicon.ico \
+ ${top_srcdir}/demo/keyboard.png \
${top_srcdir}/demo/styles.css \
${top_srcdir}/demo/print-styles.css \
${top_srcdir}/demo/vt100.js \
@rm -f "$@"
ln "$?" "$@"
+${top_srcdir}/demo/keyboard.png: ${top_srcdir}/shellinabox/keyboard.png
+ @rm -f "$@"
+ ln "$?" "$@"
+
${top_srcdir}/demo/styles.css: ${top_srcdir}/shellinabox/styles.css
@rm -f "$@"
sed -e '/\[if DEFINES_COLORS\]/,/\[endif DEFINES_COLORS\]/d' "$?" >"$@"
@rm -f "$@"
ln "$?" "$@"
-shellinaboxd.1: shellinabox/shellinaboxd.man.in config.h
+shellinaboxd.1: ${top_srcdir}/shellinabox/shellinaboxd.man.in \
+ ${top_srcdir}/config.h
@src="${top_srcdir}/shellinabox/shellinaboxd.man.in"; \
echo preprocess "$$src" '>'"$@"; \
if sed -e 's/^#define \([^ ]*\).*/\1/' -e t -e d config.h | \
$(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@"; \
rm -f GNU-stack
+.png.o:
+ @echo $(OBJCOPY) "$<" "$@"
+ @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
+ "$<" "$@"
+ @-printf '\000' >GNU-stack && \
+ $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@"; \
+ rm -f GNU-stack
.html.o:
@echo $(OBJCOPY) "$<" "$@"
rm -f GNU-stack
-shellinabox/shell_in_a_box.o: shellinabox/shell_in_a_box.js config.h
+shellinabox/shell_in_a_box.o: ${top_srcdir}/shellinabox/shell_in_a_box.js \
+ ${top_srcdir}/config.h
+
+${top_srcdir}/shellinabox/vt100.js: ${top_srcdir}/shellinabox/vt100.jspp \
+ ${top_srcdir}/shellinabox/keyboard-layout.html
.jspp.js:
@echo preprocess "$<" "$@"
- @sed -e "`sed -e 's/^#define *\([^ ]*\) *\(.*\)/\/^[^#]\/s\/\1\/\2 \\\\\/* \1 *\\\\\/\/g/' \
+ @kbd=`while read i; do \
+ printf '%s' "\`echo "$$i" | sed 's/&/\\\\\\&/g'\`"; \
+ done <${top_srcdir}/shellinabox/keyboard-layout.html`; \
+ sed -e "`sed -e 's/^#define *\([^ ]*\) *\(.*\)/\/^[^#]\/s\/\1\/\2 \\\\\/* \1 *\\\\\/\/g/' \
-e t \
-e d "$<"`" \
-e "s/^#/\/\/ #/" \
-e "s/VERSION/\"@VERSION@ (revision @VCS_REVISION@)\"/g" \
+ -e "s%KEYBOARD%'$${kbd}'%" \
"$<" >"$@"
.js.o:
shellinabox/styles.$(OBJEXT) \
shellinabox/print-styles.$(OBJEXT) \
shellinabox/enabled.$(OBJEXT) shellinabox/favicon.$(OBJEXT) \
+ shellinabox/keyboard.$(OBJEXT) \
+ shellinabox/keyboard-layout.$(OBJEXT) \
shellinabox/beep.$(OBJEXT)
shellinaboxd_OBJECTS = $(am_shellinaboxd_OBJECTS)
shellinaboxd_DEPENDENCIES = liblogging.la libhttp.la
demo/demo.jspp \
demo/demo.xml \
demo/enabled.gif \
+ demo/keyboard.png \
demo/styles.css \
demo/print-styles.css \
demo/vt100.js \
shellinabox/print-styles.css \
shellinabox/enabled.gif \
shellinabox/favicon.ico \
+ shellinabox/keyboard.png \
+ shellinabox/keyboard-layout.html \
shellinabox/beep.wav \
config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
-.SUFFIXES: .c .css .gif .html .ico .js .jspp .lo .o .obj .wav
+.SUFFIXES: .c .css .gif .html .ico .js .jspp .lo .o .obj .png .wav
am--refresh:
@:
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
shellinabox/$(DEPDIR)/$(am__dirstamp)
shellinabox/favicon.$(OBJEXT): shellinabox/$(am__dirstamp) \
shellinabox/$(DEPDIR)/$(am__dirstamp)
+shellinabox/keyboard.$(OBJEXT): shellinabox/$(am__dirstamp) \
+ shellinabox/$(DEPDIR)/$(am__dirstamp)
+shellinabox/keyboard-layout.$(OBJEXT): shellinabox/$(am__dirstamp) \
+ shellinabox/$(DEPDIR)/$(am__dirstamp)
shellinabox/beep.$(OBJEXT): shellinabox/$(am__dirstamp) \
shellinabox/$(DEPDIR)/$(am__dirstamp)
shellinaboxd$(EXEEXT): $(shellinaboxd_OBJECTS) $(shellinaboxd_DEPENDENCIES)
-rm -f shellinabox/cgi_root.$(OBJEXT)
-rm -f shellinabox/enabled.$(OBJEXT)
-rm -f shellinabox/favicon.$(OBJEXT)
+ -rm -f shellinabox/keyboard-layout.$(OBJEXT)
+ -rm -f shellinabox/keyboard.$(OBJEXT)
-rm -f shellinabox/print-styles.$(OBJEXT)
-rm -f shellinabox/root_page.$(OBJEXT)
-rm -f shellinabox/shell_in_a_box.$(OBJEXT)
${top_srcdir}/demo/demo.js: ${top_srcdir}/demo/beep.wav \
${top_srcdir}/demo/demo.jspp \
+ ${top_srcdir}/demo/enabled.gif \
${top_srcdir}/demo/favicon.ico \
+ ${top_srcdir}/demo/keyboard.png \
${top_srcdir}/demo/styles.css \
${top_srcdir}/demo/print-styles.css \
${top_srcdir}/demo/vt100.js \
@rm -f "$@"
ln "$?" "$@"
+${top_srcdir}/demo/keyboard.png: ${top_srcdir}/shellinabox/keyboard.png
+ @rm -f "$@"
+ ln "$?" "$@"
+
${top_srcdir}/demo/styles.css: ${top_srcdir}/shellinabox/styles.css
@rm -f "$@"
sed -e '/\[if DEFINES_COLORS\]/,/\[endif DEFINES_COLORS\]/d' "$?" >"$@"
@rm -f "$@"
ln "$?" "$@"
-shellinaboxd.1: shellinabox/shellinaboxd.man.in config.h
+shellinaboxd.1: ${top_srcdir}/shellinabox/shellinaboxd.man.in \
+ ${top_srcdir}/config.h
@src="${top_srcdir}/shellinabox/shellinaboxd.man.in"; \
echo preprocess "$$src" '>'"$@"; \
if sed -e 's/^#define \([^ ]*\).*/\1/' -e t -e d config.h | \
$(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@"; \
rm -f GNU-stack
+.png.o:
+ @echo $(OBJCOPY) "$<" "$@"
+ @$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
+ "$<" "$@"
+ @-printf '\000' >GNU-stack && \
+ $(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@"; \
+ rm -f GNU-stack
+
.html.o:
@echo $(OBJCOPY) "$<" "$@"
@$(OBJCOPY) -I binary `$(objcopyflags)` `echo "$<" | $(renamesymbols)`\
$(OBJCOPY) --add-section .note.GNU-stack=GNU-stack "$@"; \
rm -f GNU-stack
-shellinabox/shell_in_a_box.o: shellinabox/shell_in_a_box.js config.h
+shellinabox/shell_in_a_box.o: ${top_srcdir}/shellinabox/shell_in_a_box.js \
+ ${top_srcdir}/config.h
+
+${top_srcdir}/shellinabox/vt100.js: ${top_srcdir}/shellinabox/vt100.jspp \
+ ${top_srcdir}/shellinabox/keyboard-layout.html
.jspp.js:
@echo preprocess "$<" "$@"
- @sed -e "`sed -e 's/^#define *\([^ ]*\) *\(.*\)/\/^[^#]\/s\/\1\/\2 \\\\\/* \1 *\\\\\/\/g/' \
+ @kbd=`while read i; do \
+ printf '%s' "\`echo "$$i" | sed 's/&/\\\\\\&/g'\`"; \
+ done <${top_srcdir}/shellinabox/keyboard-layout.html`; \
+ sed -e "`sed -e 's/^#define *\([^ ]*\) *\(.*\)/\/^[^#]\/s\/\1\/\2 \\\\\/* \1 *\\\\\/\/g/' \
-e t \
-e d "$<"`" \
-e "s/^#/\/\/ #/" \
-e "s/VERSION/\"@VERSION@ (revision @VCS_REVISION@)\"/g" \
+ -e "s%KEYBOARD%'$${kbd}'%" \
"$<" >"$@"
.js.o:
#define STDC_HEADERS 1
/* Most recent revision number in the version control system */
-#define VCS_REVISION "220"
+#define VCS_REVISION "221"
/* Version number of package */
#define VERSION "2.10"
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-VCS_REVISION=220
+VCS_REVISION=221
cat >>confdefs.h <<_ACEOF
dnl This is the one location where the authoritative version number is stored
AC_INIT(shellinabox, 2.10, markus@shellinabox.com)
-VCS_REVISION=220
+VCS_REVISION=221
AC_SUBST(VCS_REVISION)
AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}",
[Most recent revision number in the version control system])
#vt100 a {
- text-decoration: none;
- color: inherit;
+ text-decoration: none;
+ color: inherit;
}
#vt100 a:hover {
- text-decoration: underline;
+ text-decoration: underline;
}
#vt100 #reconnect {
- position: absolute;
- z-index: 2;
+ position: absolute;
+ z-index: 2;
}
#vt100 #reconnect input {
- padding: 1ex;
- font-weight: bold;
- font-size: x-large;
+ padding: 1ex;
+ font-weight: bold;
+ font-size: x-large;
}
#vt100 #cursize {
- background: #EEEEEE;
- border: 1px solid black;
- font-family: sans-serif;
- font-size: large;
- font-weight: bold;
- padding: 1ex;
- position: absolute;
- z-index: 2;
+ background: #EEEEEE;
+ border: 1px solid black;
+ font-family: sans-serif;
+ font-size: large;
+ font-weight: bold;
+ padding: 1ex;
+ position: absolute;
+ z-index: 2;
}
#vt100 pre {
- margin: 0px;
+ margin: 0px;
}
#vt100 pre pre {
- overflow: hidden;
+ overflow: hidden;
}
#vt100 #scrollable {
- overflow-x: hidden;
- overflow-y: scroll;
- position: relative;
- padding: 1px;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ position: relative;
+ padding: 1px;
}
#vt100 #console, #vt100 #alt_console, #vt100 #cursor, #vt100 #lineheight, #vt100 .hidden pre {
- font-family: "DejaVu Sans Mono", "Everson Mono", FreeMono, "Andale Mono", "Lucida Console", monospace;
+ font-family: "DejaVu Sans Mono", "Everson Mono", FreeMono, "Andale Mono", "Lucida Console", monospace;
}
#vt100 #lineheight {
- position: absolute;
- visibility: hidden;
+ position: absolute;
+ visibility: hidden;
}
#vt100 #cursor {
- position: absolute;
- left: 0px;
- top: 0px;
- overflow: hidden;
- z-index: 1;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ overflow: hidden;
+ z-index: 1;
}
#vt100 #cursor.bright {
- background-color: #e60000;
- color: white;
+ background-color: #e60000;
+ color: white;
}
#vt100 #cursor.dim {
- visibility: hidden;
+ visibility: hidden;
}
#vt100 #cursor.inactive {
- border: 1px solid #e60000;
- margin: -1px;
+ border: 1px solid #e60000;
+ margin: -1px;
}
#vt100 #padding {
- visibility: hidden;
- width: 1px;
- height: 0px;
- overflow: hidden;
+ visibility: hidden;
+ width: 1px;
+ height: 0px;
+ overflow: hidden;
}
#vt100 .hidden {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 0px;
- height: 0px;
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+ width: 0px;
+ height: 0px;
}
#vt100 #menu {
- overflow: visible;
- position: absolute;
- z-index: 3;
+ overflow: visible;
+ position: absolute;
+ z-index: 3;
}
#vt100 #menu .popup {
- background-color: #EEEEEE;
- border: 1px solid black;
- font-family: sans-serif;
- position: absolute;
+ background-color: #EEEEEE;
+ border: 1px solid black;
+ font-family: sans-serif;
+ position: absolute;
}
#vt100 #menu .popup ul {
- list-style-type: none;
- padding: 0px;
- margin: 0px;
- min-width: 10em;
+ list-style-type: none;
+ padding: 0px;
+ margin: 0px;
+ min-width: 10em;
}
#vt100 #menu .popup li {
- padding: 3px 0.5ex 3px 0.5ex;
+ padding: 3px 0.5ex 3px 0.5ex;
}
#vt100 #menu .popup li.hover {
- background-color: #444444;
- color: white;
+ background-color: #444444;
+ color: white;
}
#vt100 #menu .popup li.disabled {
- color: #AAAAAA;
+ color: #AAAAAA;
}
#vt100 #menu .popup hr {
- margin: 0.5ex 0px 0.5ex 0px;
+ margin: 0.5ex 0px 0.5ex 0px;
}
#vt100 #menu img {
- margin-right: 0.5ex;
- width: 1ex;
- height: 1ex;
+ margin-right: 0.5ex;
+ width: 1ex;
+ height: 1ex;
}
#vt100 #scrollable.inverted { color: #ffffff;
background-color: #000000; }
+#vt100 #kbd_button {
+ float: left;
+ position: fixed;
+ z-index: 0;
+ visibility: hidden;
+}
+
+#vt100 #keyboard {
+ z-index: 3;
+ position: absolute;
+}
+
+#vt100 #keyboard .box {
+ font-family: sans-serif;
+ background-color: #cccccc;
+ padding: .8em;
+ float: left;
+ position: absolute;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+ box-shadow: 4px 4px 6px #222222;
+ -webkit-box-shadow: 4px 4px 6px #222222;
+ /* Don't set the -moz-box-shadow. It doesn't properly scale when CSS
+ * transforms are in effect. Once Firefox supports box-shadow, it should
+ * automatically do the right thing. Until then, leave shadows disabled
+ * for Firefox.
+ */
+ opacity: 0.85;
+ -moz-opacity: 0.85;
+ filter: alpha(opacity=85);
+}
+
+#vt100 #keyboard .box * {
+ vertical-align: top;
+ display: inline-block;
+}
+
+#vt100 #keyboard b, #vt100 #keyboard i, #vt100 #keyboard s, #vt100 #keyboard u {
+ font-style: normal;
+ font-weight: bold;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ background-color: #555555;
+ color: #eeeeee;
+ box-shadow: 2px 2px 3px #222222;
+ -webkit-box-shadow: 2px 2px 3px #222222;
+ padding: 4px;
+ margin: 2px;
+ height: 2ex;
+ display: inline-block;
+ text-align: center;
+ text-decoration: none;
+}
+
+#vt100 #keyboard b, #vt100 #keyboard s {
+ width: 2ex;
+}
+
+#vt100 #keyboard u, #vt100 #keyboard s {
+ visibility: hidden;
+}
+
+#vt100 #keyboard .shifted {
+ display: none;
+}
+
+#vt100 #keyboard .selected {
+ color: #888888;
+ background-color: #eeeeee;
+ box-shadow: 0px 0px 3px #222222;
+ -webkit-box-shadow: 0px 0px 3px #222222;
+ position: relative;
+ top: 1px;
+ left: 1px;
+}
+
+
@media print {
#vt100 .scrollback {
- display: none;
+ display: none;
}
- #vt100 #reconnect, #vt100 #cursor, #vt100 #menu {
- visibility: hidden;
+ #vt100 #reconnect, #vt100 #cursor, #vt100 #menu, #vt100 #kbd_button, #vt100 #keyboard {
+ visibility: hidden;
}
#vt100 #scrollable {
- overflow: hidden;
+ overflow: hidden;
}
#vt100 #console, #vt100 #alt_console {
- overflow: hidden;
- width: 1000000ex;
+ overflow: hidden;
+ width: 1000000ex;
}
}
this.enableAlternateScreen(false);
var wasCompressed = false;
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter' ];
- for (var i = 0; i < styles.length; ++i) {
- if (typeof this.console[0].style[styles[i]] != 'undefined') {
- for (var j = 0; j < 1; ++j) {
- wasCompressed |= this.console[j].style[styles[i]] != '';
- this.console[j].style[styles[i]] = '';
- }
- this.cursor.style[styles[i]] = '';
- this.space.style[styles[i]] = '';
- if (styles[i] == 'filter') {
- this.console[this.currentScreen].style.width = '';
- }
- break;
+ var transform = this.getTransformName();
+ if (transform) {
+ for (var i = 0; i < 2; ++i) {
+ wasCompressed |= this.console[i].style[transform] != '';
+ this.console[i].style[transform] = '';
+ }
+ this.cursor.style[transform] = '';
+ this.space.style[transform] = '';
+ if (transform == 'filter') {
+ this.console[this.currentScreen].style.width = '';
}
}
this.scale = 1.0;
};
VT100.prototype.addListener = function(elem, event, listener) {
- if (elem.addEventListener) {
- elem.addEventListener(event, listener, false);
- } else {
- elem.attachEvent('on' + event, listener);
+ try {
+ if (elem.addEventListener) {
+ elem.addEventListener(event, listener, false);
+ } else {
+ elem.attachEvent('on' + event, listener);
+ }
+ } catch (e) {
}
};
// Compute hash signature to identify the entries in the userCSS menu.
// If the menu is unchanged from last time, default values can be
// looked up in a cookie associated with this page.
- this.signature = 2;
+ this.signature = 3;
this.utfPreferred = true;
this.visualBell = typeof suppressAllAudio != 'undefined' &&
suppressAllAudio;
this.autoprint = true;
+ this.softKeyboard = false;
this.blinkingCursor = true;
if (this.visualBell) {
this.signature = Math.floor(16807*this.signature + 1) %
if (settings >= 0) {
settings = document.cookie.substr(settings + key.length).
replace(/([0-1]*).*/, "$1");
- if (settings.length == 3 + (typeof userCSSList == 'undefined' ?
+ if (settings.length == 5 + (typeof userCSSList == 'undefined' ?
0 : userCSSList.length)) {
this.utfPreferred = settings.charAt(0) != '0';
this.visualBell = settings.charAt(1) != '0';
this.autoprint = settings.charAt(2) != '0';
- this.blinkingCursor = settings.charAt(3) != '0';
+ this.softKeyboard = settings.charAt(3) != '0';
+ this.blinkingCursor = settings.charAt(4) != '0';
if (typeof userCSSList != 'undefined') {
for (var i = 0; i < userCSSList.length; ++i) {
- userCSSList[i][2] = settings.charAt(i + 3) != '0';
+ userCSSList[i][2] = settings.charAt(i + 5) != '0';
}
}
}
(this.utfEnabled ? '1' : '0') +
(this.visualBell ? '1' : '0') +
(this.autoprint ? '1' : '0') +
+ (this.softKeyboard ? '1' : '0') +
(this.blinkingCursor ? '1' : '0');
if (typeof userCSSList != 'undefined') {
for (var i = 0; i < userCSSList.length; ++i) {
label.textContent= label.textContent;
}
- // User style sheets are number sequentially
+ // User style sheets are numbered sequentially
var sheet = document.getElementById(
'usercss-' + i);
if (i == current) {
}
};
+VT100.prototype.resetLastSelectedKey = function(e) {
+ var key = this.lastSelectedKey;
+ if (!key) {
+ return false;
+ }
+
+ var position = this.mousePosition(e);
+
+ // We don't get all the necessary events to reliably reselect a key
+ // if we moved away from it and then back onto it. We approximate the
+ // behavior by remembering the key until either we release the mouse
+ // button (we might never get this event if the mouse has since left
+ // the window), or until we move away too far.
+ var box = this.keyboard.firstChild;
+ if (position[0] < box.offsetLeft + key.offsetWidth ||
+ position[1] < box.offsetTop + key.offsetHeight ||
+ position[0] >= box.offsetLeft + box.offsetWidth - key.offsetWidth ||
+ position[1] >= box.offsetTop + box.offsetHeight - key.offsetHeight ||
+ position[0] < box.offsetLeft + key.offsetLeft - key.offsetWidth ||
+ position[1] < box.offsetTop + key.offsetTop - key.offsetHeight ||
+ position[0] >= box.offsetLeft + key.offsetLeft + 2*key.offsetWidth ||
+ position[1] >= box.offsetTop + key.offsetTop + 2*key.offsetHeight) {
+ if (this.lastSelectedKey.className) log.console('reset: deselecting');
+ this.lastSelectedKey.className = '';
+ this.lastSelectedKey = undefined;
+ }
+ return false;
+};
+
+VT100.prototype.showShiftState = function(state) {
+ var style = document.getElementById('shift_state');
+ if (state) {
+ this.setTextContentRaw(style,
+ '#vt100 #keyboard .shifted {' +
+ 'display: inline }' +
+ '#vt100 #keyboard .unshifted {' +
+ 'display: none }');
+ } else {
+ this.setTextContentRaw(style, '');
+ }
+ var elems = this.keyboard.getElementsByTagName('I');
+ for (var i = 0; i < elems.length; ++i) {
+ if (elems[i].id == '16') {
+ elems[i].className = state ? 'selected' : '';
+ }
+ }
+};
+
+VT100.prototype.showCtrlState = function(state) {
+ var ctrl = this.getChildById(this.keyboard, '17' /* Ctrl */);
+ if (ctrl) {
+ ctrl.className = state ? 'selected' : '';
+ }
+};
+
+VT100.prototype.showAltState = function(state) {
+ var alt = this.getChildById(this.keyboard, '18' /* Alt */);
+ if (alt) {
+ alt.className = state ? 'selected' : '';
+ }
+};
+
+VT100.prototype.clickedKeyboard = function(e, elem, ch, key, shift, ctrl, alt){
+ var fake = [ ];
+ fake.charCode = ch;
+ fake.keyCode = key;
+ fake.ctrlKey = ctrl;
+ fake.shiftKey = shift;
+ fake.altKey = alt;
+ fake.metaKey = alt;
+ return this.handleKey(fake);
+};
+
+VT100.prototype.addKeyBinding = function(elem, ch, key, CH, KEY) {
+ if (elem == undefined) {
+ return;
+ }
+ if (ch == '\u00A0') {
+ // should be treated as a regular space character.
+ ch = ' ';
+ }
+ if (ch != undefined && CH == undefined) {
+ // For letter keys, we automatically compute the uppercase character code
+ // from the lowercase one.
+ CH = ch.toUpperCase();
+ }
+ if (KEY == undefined && key != undefined) {
+ // Most keys have identically key codes for both lowercase and uppercase
+ // keypresses. Normally, only function keys would have distinct key codes,
+ // whereas regular keys have character codes.
+ KEY = key;
+ } else if (KEY == undefined && CH != undefined) {
+ // For regular keys, copy the character code to the key code.
+ KEY = CH.charCodeAt(0);
+ }
+ if (key == undefined && ch != undefined) {
+ // For regular keys, copy the character code to the key code.
+ key = ch.charCodeAt(0);
+ }
+ // Convert characters to numeric character codes. If the character code
+ // is undefined (i.e. this is a function key), set it to zero.
+ ch = ch ? ch.charCodeAt(0) : 0;
+ CH = CH ? CH.charCodeAt(0) : 0;
+
+ // Mouse down events high light the key. We also set lastSelectedKey. This
+ // is needed to that mouseout/mouseover can keep track of the key that
+ // is currently being clicked.
+ this.addListener(elem, 'mousedown',
+ function(vt100, elem, key) { return function(e) {
+ if ((e.which || e.button) == 1) {
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className= '';
+ }
+ // Highlight the key while the mouse button is held down.
+ if (key == 16 /* Shift */) {
+ if (!elem.className != vt100.isShift) {
+ vt100.showShiftState(!vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className != vt100.isCtrl) {
+ vt100.showCtrlState(!vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className != vt100.isAlt) {
+ vt100.showAltState(!vt100.isAlt);
+ }
+ } else {
+ elem.className = 'selected';
+ }
+ vt100.lastSelectedKey = elem;
+ }
+ return false; }; }(this, elem, key));
+ var clicked =
+ // Modifier keys update the state of the keyboard, but do not generate
+ // any key clicks that get forwarded to the application.
+ key >= 16 /* Shift */ && key <= 18 /* Alt */ ?
+ function(vt100, elem) { return function(e) {
+ if (elem == vt100.lastSelectedKey) {
+ if (key == 16 /* Shift */) {
+ // The user clicked the Shift key
+ vt100.isShift = !vt100.isShift;
+ vt100.showShiftState(vt100.isShift);
+ } else if (key == 17 /* Ctrl */) {
+ vt100.isCtrl = !vt100.isCtrl;
+ vt100.showCtrlState(vt100.isCtrl);
+ } else if (key == 18 /* Alt */) {
+ vt100.isAlt = !vt100.isAlt;
+ vt100.showAltState(vt100.isAlt);
+ }
+ vt100.lastSelectedKey = undefined;
+ }
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ return false; }; }(this, elem) :
+ // Regular keys generate key clicks, when the mouse button is released or
+ // when a mouse click event is received.
+ function(vt100, elem, ch, key, CH, KEY) { return function(e) {
+ if (vt100.lastSelectedKey) {
+ if (elem == vt100.lastSelectedKey) {
+ // The user clicked a key.
+ if (vt100.isShift) {
+ vt100.clickedKeyboard(e, elem, CH, KEY,
+ true, vt100.isCtrl, vt100.isAlt);
+ } else {
+ vt100.clickedKeyboard(e, elem, ch, key,
+ false, vt100.isCtrl, vt100.isAlt);
+ }
+ vt100.isShift = false;
+ vt100.showShiftState(false);
+ vt100.isCtrl = false;
+ vt100.showCtrlState(false);
+ vt100.isAlt = false;
+ vt100.showAltState(false);
+ }
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ elem.className = '';
+ return false; }; }(this, elem, ch, key, CH, KEY);
+ this.addListener(elem, 'mouseup', clicked);
+ this.addListener(elem, 'click', clicked);
+
+ // When moving the mouse away from a key, check if any keys need to be
+ // deselected.
+ this.addListener(elem, 'mouseout',
+ function(vt100, elem, key) { return function(e) {
+ if (key == 16 /* Shift */) {
+ if (!elem.className == vt100.isShift) {
+ vt100.showShiftState(vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className == vt100.isCtrl) {
+ vt100.showCtrlState(vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className == vt100.isAlt) {
+ vt100.showAltState(vt100.isAlt);
+ }
+ } else if (elem.className) {
+ elem.className = '';
+ vt100.lastSelectedKey = elem;
+ } else if (vt100.lastSelectedKey) {
+ vt100.resetLastSelectedKey(e);
+ }
+ return false; }; }(this, elem, key));
+
+ // When moving the mouse over a key, select it if the user is still holding
+ // the mouse button down (i.e. elem == lastSelectedKey)
+ this.addListener(elem, 'mouseover',
+ function(vt100, elem, key) { return function(e) {
+ if (elem == vt100.lastSelectedKey) {
+ if (key == 16 /* Shift */) {
+ if (!elem.className != vt100.isShift) {
+ vt100.showShiftState(!vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className != vt100.isCtrl) {
+ vt100.showCtrlState(!vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className != vt100.isAlt) {
+ vt100.showAltState(!vt100.isAlt);
+ }
+ } else if (!elem.className) {
+ elem.className = 'selected';
+ }
+ } else {
+ vt100.resetLastSelectedKey(e);
+ }
+ return false; }; }(this, elem, key));
+};
+
+VT100.prototype.initializeKeyBindings = function(elem) {
+ if (elem) {
+ if (elem.nodeName == "I" || elem.nodeName == "B") {
+ if (elem.id) {
+ // Function keys. The Javascript keycode is part of the "id"
+ var i = parseInt(elem.id);
+ if (i) {
+ // If the id does not parse as a number, it is not a keycode.
+ this.addKeyBinding(elem, undefined, i);
+ }
+ } else {
+ var child = elem.firstChild;
+ if (child.nodeName == "#text") {
+ // If the key only has a text node as a child, then it is a letter.
+ // Automatically compute the lower and upper case version of the key.
+ this.addKeyBinding(elem, this.getTextContent(child).toLowerCase());
+ } else {
+ // If the key has two children, they are the lower and upper case
+ // character code, respectively.
+ this.addKeyBinding(elem, this.getTextContent(child), undefined,
+ this.getTextContent(child.nextSibling));
+ }
+ }
+ }
+ }
+ // Recursively parse all other child nodes.
+ for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ this.initializeKeyBindings(elem);
+ }
+};
+
+VT100.prototype.initializeKeyboard = function() {
+ // Configure mouse event handlers for button that displays/hides keyboard
+ var box = this.keyboard.firstChild;
+ this.hideSoftKeyboard();
+ this.addListener(this.keyboardImage, 'click',
+ function(vt100) { return function(e) {
+ if (vt100.keyboard.style.display != '') {
+ if (vt100.reconnectBtn.style.visibility != '') {
+ vt100.showSoftKeyboard();
+ }
+ } else {
+ vt100.hideSoftKeyboard();
+ vt100.input.focus();
+ }
+ return false; }; }(this));
+
+ // Enable button that displays keyboard
+ if (this.softKeyboard) {
+ this.keyboardImage.style.visibility = 'visible';
+ }
+
+ // Configure mouse event handlers for on-screen keyboard
+ this.addListener(this.keyboard, 'click',
+ function(vt100) { return function(e) {
+ vt100.hideSoftKeyboard();
+ vt100.input.focus();
+ return false; }; }(this));
+ this.addListener(this.keyboard, 'selectstart', this.cancelEvent);
+ this.addListener(box, 'click', this.cancelEvent);
+ this.addListener(box, 'mouseup',
+ function(vt100) { return function(e) {
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ return false; }; }(this));
+ this.addListener(box, 'mouseout',
+ function(vt100) { return function(e) {
+ return vt100.resetLastSelectedKey(e); }; }(this));
+ this.addListener(box, 'mouseover',
+ function(vt100) { return function(e) {
+ return vt100.resetLastSelectedKey(e); }; }(this));
+
+ // Configure SHIFT key behavior
+ var style = document.createElement('style');
+ var id = document.createAttribute('id');
+ id.nodeValue = 'shift_state';
+ style.setAttributeNode(id);
+ var type = document.createAttribute('type');
+ type.nodeValue = 'text/css';
+ style.setAttributeNode(type);
+ document.getElementsByTagName('head')[0].appendChild(style);
+
+ // Set up key bindings
+ this.initializeKeyBindings(box);
+};
+
VT100.prototype.initializeElements = function(container) {
// If the necessary objects have not already been defined in the HTML
// page, create them now.
if (!this.getChildById(this.container, 'reconnect') ||
!this.getChildById(this.container, 'menu') ||
+ !this.getChildById(this.container, 'keyboard') ||
+ !this.getChildById(this.container, 'kbd_button') ||
+ !this.getChildById(this.container, 'kbd_img') ||
!this.getChildById(this.container, 'scrollable') ||
!this.getChildById(this.container, 'console') ||
!this.getChildById(this.container, 'alt_console') ||
'<div id="cursize" style="visibility: hidden">' +
'</div>' +
'<div id="menu"></div>' +
+ '<div id="keyboard" unselectable="on">' +
+ '<pre class="box"><div><i id="27">Esc</i><i id="112">F1</i><i id="113">F2</i><i id="114">F3</i><i id="115">F4</i><i id="116">F5</i><i id="117">F6</i><i id="118">F7</i><i id="119">F8</i><i id="120">F9</i><i id="121">F10</i><i id="122">F11</i><i id="123">F12</i><br /><b><span class="unshifted">`</span><span class="shifted">~</span></b><b><span class="unshifted">1</span><span class="shifted">!</span></b><b><span class="unshifted">2</span><span class="shifted">@</span></b><b><span class="unshifted">3</span><span class="shifted">#</span></b><b><span class="unshifted">4</span><span class="shifted">$</span></b><b><span class="unshifted">5</span><span class="shifted">%</span></b><b><span class="unshifted">6</span><span class="shifted">^</span></b><b><span class="unshifted">7</span><span class="shifted">&</span></b><b><span class="unshifted">8</span><span class="shifted">*</span></b><b><span class="unshifted">9</span><span class="shifted">(</span></b><b><span class="unshifted">0</span><span class="shifted">)</span></b><b><span class="unshifted">-</span><span class="shifted">_</span></b><b><span class="unshifted">=</span><span class="shifted">+</span></b><i id="8"> ← </i><br /><i id="9">Tab</i><b>Q</b><b>W</b><b>E</b><b>R</b><b>T</b><b>Y</b><b>U</b><b>I</b><b>O</b><b>P</b><b><span class="unshifted">[</span><span class="shifted">{</span></b><b><span class="unshifted">]</span><span class="shifted">}</span></b><b><span class="unshifted">\</span><span class="shifted">|</span></b><br /><u>Tab </u><b>A</b><b>S</b><b>D</b><b>F</b><b>G</b><b>H</b><b>J</b><b>K</b><b>L</b><b><span class="unshifted">;</span><span class="shifted">:</span></b><b><span class="unshifted">'</span><span class="shifted">"</span></b><i id="13">Enter</i><br /><u> </u><i id="16">Shift</i><b>Z</b><b>X</b><b>C</b><b>V</b><b>B</b><b>N</b><b>M</b><b><span class="unshifted">,</span><span class="shifted"><</span></b><b><span class="unshifted">.</span><span class="shifted">></span></b><b><span class="unshifted">/</span><span class="shifted">?</span></b><i id="16">Shift</i><br /><u>XXX</u><i id="17">Ctrl</i><i id="18">Alt</i><i style="width: 25ex"> </i></div> <div><i id="45">Ins</i><i id="46">Del</i><i id="36">Home</i><i id="35">End</i><br /><u> </u><br /><u> </u><br /><u>Ins</u><s> </s><b id="38">↑</b><s> </s><u> </u><b id="33">⇑</b><br /><u>Ins</u><b id="37">←</b><b id="40">↓</b><b id="39">→</b><u> </u><b id="34">⇓</b></div></pre>' +
+ '</div>' +
'<div id="scrollable">' +
+ '<table id="kbd_button">' +
+ '<tr><td width="100%"> </td>' +
+ '<td><img id="kbd_img" src="keyboard.png" /></td>' +
+ '<td> </td></tr>' +
+ '</table>' +
'<pre id="lineheight"> </pre>' +
'<pre id="console">' +
'<pre></pre>' +
this.reconnectBtn = this.getChildById(this.container,'reconnect');
this.curSizeBox = this.getChildById(this.container, 'cursize');
this.menu = this.getChildById(this.container, 'menu');
+ this.keyboard = this.getChildById(this.container, 'keyboard');
+ this.keyboardImage = this.getChildById(this.container, 'kbd_img');
this.scrollable = this.getChildById(this.container,
'scrollable');
this.lineheight = this.getChildById(this.container,
// Hide context menu
this.hideContextMenu();
+ // Set up onscreen soft keyboard
+ this.initializeKeyboard();
+
// Add listener to reconnect button
this.addListener(this.reconnectBtn.firstChild, 'click',
function(vt100) {
VT100.prototype.showReconnect = function(state) {
if (state) {
+ this.hideSoftKeyboard();
this.reconnectBtn.style.visibility = '';
} else {
this.reconnectBtn.style.visibility = 'hidden';
};
VT100.prototype.resizer = function() {
+ // Hide onscreen soft keyboard
+ this.hideSoftKeyboard();
+
// The cursor can get corrupted if the print-preview is displayed in Firefox.
// Recreating it, will repair it.
var newCursor = document.createElement('pre');
return false;
};
+VT100.prototype.mousePosition = function(event) {
+ var offsetX = this.container.offsetLeft;
+ var offsetY = this.container.offsetTop;
+ for (var e = this.container; e = e.offsetParent; ) {
+ offsetX += e.offsetLeft;
+ offsetY += e.offsetTop;
+ }
+ return [ event.clientX - offsetX,
+ event.clientY - offsetY ];
+};
+
VT100.prototype.mouseEvent = function(event, type) {
// If any text is currently selected, do not move the focus as that would
// invalidate the selection.
}
// Compute mouse position in characters.
- var offsetX = this.container.offsetLeft;
- var offsetY = this.container.offsetTop;
- for (var e = this.container; e = e.offsetParent; ) {
- offsetX += e.offsetLeft;
- offsetY += e.offsetTop;
- }
- var x = (event.clientX - offsetX) / this.cursorWidth;
- var y = ((event.clientY - offsetY) + this.scrollable.offsetTop) /
- this.cursorHeight - this.numScrollbackLines;
+ var position = this.mousePosition(event);
+ var x = Math.floor(position[0] / this.cursorWidth);
+ var y = Math.floor((position[1] + this.scrollable.scrollTop) /
+ this.cursorHeight) - this.numScrollbackLines;
var inside = true;
if (x >= this.terminalWidth) {
x = this.terminalWidth - 1;
// Bring up context menu.
if (button == 2 && !event.shiftKey) {
if (type == 0 /* MOUSE_DOWN */) {
- this.showContextMenu(event.clientX - offsetX, event.clientY - offsetY);
+ this.showContextMenu(position[0], position[1]);
}
return this.cancelEvent(event);
}
(typeof elem.textContent == 'undefined' ? elem.innerText : '');
};
+VT100.prototype.setTextContentRaw = function(elem, s) {
+ // Updating the content of an element is an expensive operation. It actually
+ // pays off to first check whether the element is still unchanged.
+ if (typeof elem.textContent == 'undefined') {
+ if (elem.innerText != s) {
+ try {
+ elem.innerText = s;
+ } catch (e) {
+ // Very old versions of IE do not allow setting innerText. Instead,
+ // remove all children, by setting innerHTML and then set the text
+ // using DOM methods.
+ elem.innerHTML = '';
+ elem.appendChild(document.createTextNode(
+ this.replaceChar(s, ' ', '\u00A0')));
+ }
+ }
+ } else {
+ if (elem.textContent != s) {
+ elem.textContent = s;
+ }
+ }
+};
+
VT100.prototype.setTextContent = function(elem, s) {
// Check if we find any URLs in the text. If so, automatically convert them
// to links.
return;
}
- // Updating the content of an element is an expensive operation. It actually
- // pays off to first check whether the element is still unchanged.
- if (typeof elem.textContent == 'undefined') {
- if (elem.innerText != s) {
- try {
- elem.innerText = s;
- } catch (e) {
- // Very old versions of IE do not allow setting innerText. Instead,
- // remove all children, by setting innerHTML and then set the text
- // using DOM methods.
- elem.innerHTML = '';
- elem.appendChild(document.createTextNode(
- this.replaceChar(s, ' ', '\u00A0')));
- }
- }
- } else {
- if (elem.textContent != s) {
- elem.textContent = s;
- }
- }
+ this.setTextContentRaw(elem, s);
};
VT100.prototype.insertBlankLine = function(y, color, style) {
this.console[this.currentScreen].style.display = '';
// Select appropriate character pitch.
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter' ];
- for (var i = 0; i < styles.length; ++i) {
- if (typeof this.console[0].style[styles[i]] != 'undefined') {
- if (state) {
- // Upon enabling the alternate screen, we switch to 80 column mode. But
- // upon returning to the regular screen, we restore the mode that was
- // in effect previously.
- this.console[1].style[styles[i]] = '';
- }
- var style =
- this.console[this.currentScreen].style[styles[i]];
- this.cursor.style[styles[i]] = style;
- this.space.style[styles[i]] = style;
- this.scale = style == '' ? 1.0:1.65;
- if (styles[i] == 'filter') {
- this.console[this.currentScreen].style.width = style == '' ? '165%':'';
- }
- break;
+ var transform = this.getTransformName();
+ if (transform) {
+ if (state) {
+ // Upon enabling the alternate screen, we switch to 80 column mode. But
+ // upon returning to the regular screen, we restore the mode that was
+ // in effect previously.
+ this.console[1].style[transform] = '';
+ }
+ var style =
+ this.console[this.currentScreen].style[transform];
+ this.cursor.style[transform] = style;
+ this.space.style[transform] = style;
+ this.scale = style == '' ? 1.0:1.65;
+ if (transform == 'filter') {
+ this.console[this.currentScreen].style.width = style == '' ? '165%':'';
}
}
this.resizer();
this.visualBell = !this.visualBell;
};
+VT100.prototype.toggleSoftKeyboard = function() {
+ this.softKeyboard = !this.softKeyboard;
+ this.keyboardImage.style.visibility = this.softKeyboard ? 'visible' : '';
+};
+
+VT100.prototype.deselectKeys = function(elem) {
+ if (elem && elem.className == 'selected') {
+ elem.className = '';
+ }
+ for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ this.deselectKeys(elem);
+ }
+};
+
+VT100.prototype.showSoftKeyboard = function() {
+ // Make sure no key is currently selected
+ this.lastSelectedKey = undefined;
+ this.deselectKeys(this.keyboard);
+ this.isShift = false;
+ this.showShiftState(false);
+ this.isCtrl = false;
+ this.showCtrlState(false);
+ this.isAlt = false;
+ this.showAltState(false);
+
+ this.keyboard.style.left = '0px';
+ this.keyboard.style.top = '0px';
+ this.keyboard.style.width = this.container.offsetWidth + 'px';
+ this.keyboard.style.height = this.container.offsetHeight + 'px';
+ this.keyboard.style.visibility = 'hidden';
+ this.keyboard.style.display = '';
+
+ var kbd = this.keyboard.firstChild;
+ var scale = 1.0;
+ var transform = this.getTransformName();
+ if (transform) {
+ kbd.style[transform] = '';
+ if (kbd.offsetWidth > 0.9 * this.container.offsetWidth) {
+ scale = (kbd.offsetWidth/
+ this.container.offsetWidth)/0.9;
+ }
+ if (kbd.offsetHeight > 0.9 * this.container.offsetHeight) {
+ scale = Math.max((kbd.offsetHeight/
+ this.container.offsetHeight)/0.9);
+ }
+ var style = this.getTransformStyle(transform,
+ scale > 1.0 ? scale : undefined);
+ kbd.style[transform] = style;
+ }
+ if (transform == 'filter') {
+ scale = 1.0;
+ }
+ kbd.style.left = ((this.container.offsetWidth -
+ kbd.offsetWidth/scale)/2) + 'px';
+ kbd.style.top = ((this.container.offsetHeight -
+ kbd.offsetHeight/scale)/2) + 'px';
+
+ this.keyboard.style.visibility = 'visible';
+};
+
+VT100.prototype.hideSoftKeyboard = function() {
+ this.keyboard.style.display = 'none';
+};
+
VT100.prototype.toggleCursorBlinking = function() {
this.blinkingCursor = !this.blinkingCursor;
};
VT100.prototype.about = function() {
- alert("VT100 Terminal Emulator " + "2.10 (revision 220)" +
+ alert("VT100 Terminal Emulator " + "2.10 (revision 221)" +
"\nCopyright 2008-2010 by Markus Gutschke\n" +
"For more information check http://shellinabox.com");
};
'<li>' +
(this.visualBell ? '<img src="enabled.gif" />' : '') +
'Visual Bell</li>'+
+ '<li>' +
+ (this.softKeyboard ? '<img src="enabled.gif" />' : '') +
+ 'Onscreen Keyboard</li>' +
'<li id="endconfig">' +
(this.blinkingCursor ? '<img src="enabled.gif" />' : '') +
'Blinking Cursor</li>'+
// Actions for default items
var actions = [ this.copyLast, p, this.reset,
this.toggleUTF, this.toggleBell,
+ this.toggleSoftKeyboard,
this.toggleCursorBlinking ];
// Actions for user CSS styles (if any)
}
// Position menu next to the mouse pointer
- if (x + popup.clientWidth > this.container.offsetWidth) {
- x = this.container.offsetWidth - popup.clientWidth;
+ this.menu.style.left = '0px';
+ this.menu.style.top = '0px';
+ this.menu.style.width = this.container.offsetWidth + 'px';
+ this.menu.style.height = this.container.offsetHeight + 'px';
+ popup.style.left = '0px';
+ popup.style.top = '0px';
+
+ var margin = 2;
+ if (x + popup.clientWidth >= this.container.offsetWidth - margin) {
+ x = this.container.offsetWidth-popup.clientWidth - margin - 1;
}
- if (x < 0) {
- x = 0;
+ if (x < margin) {
+ x = margin;
}
- if (y + popup.clientHeight > this.container.offsetHeight) {
- y = this.container.offsetHeight-popup.clientHeight;
+ if (y + popup.clientHeight >= this.container.offsetHeight - margin) {
+ y = this.container.offsetHeight-popup.clientHeight - margin - 1;
}
- if (y < 0) {
- y = 0;
+ if (y < margin) {
+ y = margin;
}
popup.style.left = x + 'px';
popup.style.top = y + 'px';
// Block all other interactions with the terminal emulator
- this.menu.style.left = '0px';
- this.menu.style.top = '0px';
- this.menu.style.width = this.container.offsetWidth + 'px';
- this.menu.style.height = this.container.offsetHeight + 'px';
this.addListener(this.menu, 'click', function(vt100) {
return function() {
vt100.hideContextMenu();
this.savedY[this.currentScreen]);
};
-VT100.prototype.set80_132Mode = function(state) {
- var transform = undefined;
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter'
- ];
+VT100.prototype.getTransformName = function() {
+ var styles = [ 'transform', 'WebkitTransform', 'MozTransform', 'filter' ];
for (var i = 0; i < styles.length; ++i) {
if (typeof this.console[0].style[styles[i]] != 'undefined') {
- transform = styles[i];
- break;
+ return styles[i];
}
}
+ return undefined;
+};
+VT100.prototype.getTransformStyle = function(transform, scale) {
+ return scale && scale != 1.0
+ ? transform == 'filter'
+ ? 'progid:DXImageTransform.Microsoft.Matrix(' +
+ 'M11=' + (1.0/scale) + ',M12=0,M21=0,M22=1,' +
+ "sizingMethod='auto expand')"
+ : 'translateX(-50%) ' +
+ 'scaleX(' + (1.0/scale) + ') ' +
+ 'translateX(50%)'
+ : '';
+};
+
+VT100.prototype.set80_132Mode = function(state) {
+ var transform = this.getTransformName();
if (transform) {
if ((this.console[this.currentScreen].style[transform] != '') == state) {
return;
}
- var style =
- state ? transform == 'filter'
- ? 'progid:DXImageTransform.Microsoft.Matrix(' +
- 'M11=0.606060606060606060606,M12=0,M21=0,M22=1,' +
- "sizingMethod='auto expand')"
- : 'translateX(-50%) ' +
- 'scaleX(0.606060606060606060606) ' +
- 'translateX(50%)'
- : '';
+ var style = state ?
+ this.getTransformStyle(transform, 1.65):'';
this.console[this.currentScreen].style[transform] = style;
- this.cursor.style[transform] = style;
- this.space.style[transform] = style;
- this.scale = state ? 1.65 : 1.0;
+ this.cursor.style[transform] = style;
+ this.space.style[transform] = style;
+ this.scale = state ? 1.65 : 1.0;
if (transform == 'filter') {
- this.console[this.currentScreen].style.width = state ? '165%' : '';
+ this.console[this.currentScreen].style.width = state ? '165%' : '';
}
this.resizer();
}
--- /dev/null
+<pre class="box">
+ <div>
+ <i id="27">Esc</i><i id="112">F1</i><i id="113">F2</i><i id="114">F3</i>
+ <i id="115">F4</i><i id="116">F5</i><i id="117">F6</i><i id="118">F7</i>
+ <i id="119">F8</i><i id="120">F9</i><i id="121">F10</i><i id="122">F11</i>
+ <i id="123">F12</i><br />
+ <b><span class="unshifted">`</span><span class="shifted">~</span></b>
+ <b><span class="unshifted">1</span><span class="shifted">!</span></b>
+ <b><span class="unshifted">2</span><span class="shifted">@</span></b>
+ <b><span class="unshifted">3</span><span class="shifted">#</span></b>
+ <b><span class="unshifted">4</span><span class="shifted">$</span></b>
+ <b><span class="unshifted">5</span><span class="shifted">%</span></b>
+ <b><span class="unshifted">6</span><span class="shifted">^</span></b>
+ <b><span class="unshifted">7</span><span class="shifted">&</span></b>
+ <b><span class="unshifted">8</span><span class="shifted">*</span></b>
+ <b><span class="unshifted">9</span><span class="shifted">(</span></b>
+ <b><span class="unshifted">0</span><span class="shifted">)</span></b>
+ <b><span class="unshifted">-</span><span class="shifted">_</span></b>
+ <b><span class="unshifted">=</span><span class="shifted">+</span></b>
+ <i id="8"> ← </i>
+ <br />
+ <i id="9">Tab</i>
+ <b>Q</b><b>W</b><b>E</b><b>R</b><b>T</b><b>Y</b><b>U</b><b>I</b><b>O</b>
+ <b>P</b>
+ <b><span class="unshifted">[</span><span class="shifted">{</span></b>
+ <b><span class="unshifted">]</span><span class="shifted">}</span></b>
+ <b><span class="unshifted">\</span><span class="shifted">|</span></b>
+ <br />
+ <u>Tab </u>
+ <b>A</b><b>S</b><b>D</b><b>F</b><b>G</b><b>H</b><b>J</b><b>K</b><b>L</b>
+ <b><span class="unshifted">;</span><span class="shifted">:</span></b>
+ <b><span class="unshifted">'</span><span class="shifted">"</span></b>
+ <i id="13">Enter</i>
+ <br />
+ <u> </u>
+ <i id="16">Shift</i>
+ <b>Z</b><b>X</b><b>C</b><b>V</b><b>B</b><b>N</b><b>M</b>
+ <b><span class="unshifted">,</span><span class="shifted"><</span></b>
+ <b><span class="unshifted">.</span><span class="shifted">></span></b>
+ <b><span class="unshifted">/</span><span class="shifted">?</span></b>
+ <i id="16">Shift</i>
+ <br />
+ <u>XXX</u>
+ <i id="17">Ctrl</i>
+ <i id="18">Alt</i>
+ <i style="width: 25ex"> </i>
+ </div>
+
+ <div>
+ <i id="45">Ins</i><i id="46">Del</i><i id="36">Home</i><i id="35">End</i>
+ <br />
+ <u> </u><br />
+ <u> </u><br />
+ <u>Ins</u><s> </s><b id="38">↑</b><s> </s><u> </u>
+ <b id="33">⇑</b><br />
+ <u>Ins</u><b id="37">←</b><b id="40">↓</b>
+ <b id="39">→</b><u> </u><b id="34">⇓</b>
+ </div>
+</pre>
};
ShellInABox.prototype.about = function() {
- alert("Shell In A Box version " + "2.10 (revision 220)" +
+ alert("Shell In A Box version " + "2.10 (revision 221)" +
"\nCopyright 2008-2010 by Markus Gutschke\n" +
"For more information check http://shellinabox.com" +
(typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ?
extern char faviconStart[];
extern char faviconEnd[];
serveStaticFile(http, "image/x-icon", faviconStart, faviconEnd);
+ } else if (pathInfoLength == 12 && !memcmp(pathInfo, "keyboard.png", 11)) {
+ // Serve the keyboard icon
+ extern char keyboardStart[];
+ extern char keyboardEnd[];
+ serveStaticFile(http, "image/png", keyboardStart, keyboardEnd);
} else if (pathInfoLength == 14 && !memcmp(pathInfo, "ShellInABox.js", 14)) {
// Serve both vt100.js and shell_in_a_box.js in the same transaction.
// Also, indicate to the client whether the server is SSL enabled.
#vt100 a {
- text-decoration: none;
- color: inherit;
+ text-decoration: none;
+ color: inherit;
}
#vt100 a:hover {
- text-decoration: underline;
+ text-decoration: underline;
}
#vt100 #reconnect {
- position: absolute;
- z-index: 2;
+ position: absolute;
+ z-index: 2;
}
#vt100 #reconnect input {
- padding: 1ex;
- font-weight: bold;
- font-size: x-large;
+ padding: 1ex;
+ font-weight: bold;
+ font-size: x-large;
}
#vt100 #cursize {
- background: #EEEEEE;
- border: 1px solid black;
- font-family: sans-serif;
- font-size: large;
- font-weight: bold;
- padding: 1ex;
- position: absolute;
- z-index: 2;
+ background: #EEEEEE;
+ border: 1px solid black;
+ font-family: sans-serif;
+ font-size: large;
+ font-weight: bold;
+ padding: 1ex;
+ position: absolute;
+ z-index: 2;
}
#vt100 pre {
- margin: 0px;
+ margin: 0px;
}
#vt100 pre pre {
- overflow: hidden;
+ overflow: hidden;
}
#vt100 #scrollable {
- overflow-x: hidden;
- overflow-y: scroll;
- position: relative;
- padding: 1px;
+ overflow-x: hidden;
+ overflow-y: scroll;
+ position: relative;
+ padding: 1px;
}
#vt100 #console, #vt100 #alt_console, #vt100 #cursor, #vt100 #lineheight, #vt100 .hidden pre {
- font-family: "DejaVu Sans Mono", "Everson Mono", FreeMono, "Andale Mono", "Lucida Console", monospace;
+ font-family: "DejaVu Sans Mono", "Everson Mono", FreeMono, "Andale Mono", "Lucida Console", monospace;
}
#vt100 #lineheight {
- position: absolute;
- visibility: hidden;
+ position: absolute;
+ visibility: hidden;
}
#vt100 #cursor {
- position: absolute;
- left: 0px;
- top: 0px;
- overflow: hidden;
- z-index: 1;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ overflow: hidden;
+ z-index: 1;
}
#vt100 #cursor.bright {
- background-color: #e60000;
- color: white;
+ background-color: #e60000;
+ color: white;
}
#vt100 #cursor.dim {
- visibility: hidden;
+ visibility: hidden;
}
#vt100 #cursor.inactive {
- border: 1px solid #e60000;
- margin: -1px;
+ border: 1px solid #e60000;
+ margin: -1px;
}
#vt100 #padding {
- visibility: hidden;
- width: 1px;
- height: 0px;
- overflow: hidden;
+ visibility: hidden;
+ width: 1px;
+ height: 0px;
+ overflow: hidden;
}
#vt100 .hidden {
- position: absolute;
- top: -10000px;
- left: -10000px;
- width: 0px;
- height: 0px;
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+ width: 0px;
+ height: 0px;
}
#vt100 #menu {
- overflow: visible;
- position: absolute;
- z-index: 3;
+ overflow: visible;
+ position: absolute;
+ z-index: 3;
}
#vt100 #menu .popup {
- background-color: #EEEEEE;
- border: 1px solid black;
- font-family: sans-serif;
- position: absolute;
+ background-color: #EEEEEE;
+ border: 1px solid black;
+ font-family: sans-serif;
+ position: absolute;
}
#vt100 #menu .popup ul {
- list-style-type: none;
- padding: 0px;
- margin: 0px;
- min-width: 10em;
+ list-style-type: none;
+ padding: 0px;
+ margin: 0px;
+ min-width: 10em;
}
#vt100 #menu .popup li {
- padding: 3px 0.5ex 3px 0.5ex;
+ padding: 3px 0.5ex 3px 0.5ex;
}
#vt100 #menu .popup li.hover {
- background-color: #444444;
- color: white;
+ background-color: #444444;
+ color: white;
}
#vt100 #menu .popup li.disabled {
- color: #AAAAAA;
+ color: #AAAAAA;
}
#vt100 #menu .popup hr {
- margin: 0.5ex 0px 0.5ex 0px;
+ margin: 0.5ex 0px 0.5ex 0px;
}
#vt100 #menu img {
- margin-right: 0.5ex;
- width: 1ex;
- height: 1ex;
+ margin-right: 0.5ex;
+ width: 1ex;
+ height: 1ex;
}
#vt100 #scrollable.inverted { color: #ffffff;
background-color: #000000; }
+
+#vt100 #kbd_button {
+ float: left;
+ position: fixed;
+ z-index: 0;
+ visibility: hidden;
+}
+
+#vt100 #keyboard {
+ z-index: 3;
+ position: absolute;
+}
+
+#vt100 #keyboard .box {
+ font-family: sans-serif;
+ background-color: #cccccc;
+ padding: .8em;
+ float: left;
+ position: absolute;
+ border-radius: 10px;
+ -moz-border-radius: 10px;
+ box-shadow: 4px 4px 6px #222222;
+ -webkit-box-shadow: 4px 4px 6px #222222;
+ /* Don't set the -moz-box-shadow. It doesn't properly scale when CSS
+ * transforms are in effect. Once Firefox supports box-shadow, it should
+ * automatically do the right thing. Until then, leave shadows disabled
+ * for Firefox.
+ */
+ opacity: 0.85;
+ -moz-opacity: 0.85;
+ filter: alpha(opacity=85);
+}
+
+#vt100 #keyboard .box * {
+ vertical-align: top;
+ display: inline-block;
+}
+
+#vt100 #keyboard b, #vt100 #keyboard i, #vt100 #keyboard s, #vt100 #keyboard u {
+ font-style: normal;
+ font-weight: bold;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ background-color: #555555;
+ color: #eeeeee;
+ box-shadow: 2px 2px 3px #222222;
+ -webkit-box-shadow: 2px 2px 3px #222222;
+ padding: 4px;
+ margin: 2px;
+ height: 2ex;
+ display: inline-block;
+ text-align: center;
+ text-decoration: none;
+}
+
+#vt100 #keyboard b, #vt100 #keyboard s {
+ width: 2ex;
+}
+
+#vt100 #keyboard u, #vt100 #keyboard s {
+ visibility: hidden;
+}
+
+#vt100 #keyboard .shifted {
+ display: none;
+}
+
+#vt100 #keyboard .selected {
+ color: #888888;
+ background-color: #eeeeee;
+ box-shadow: 0px 0px 3px #222222;
+ -webkit-box-shadow: 0px 0px 3px #222222;
+ position: relative;
+ top: 1px;
+ left: 1px;
+}
+
[if DEFINES_COLORS]
/* IE cannot properly handle "inherit" properties. So, the monochrome.css/
* color.css style sheets cannot work, if we define colors in styles.css.
@media print {
#vt100 .scrollback {
- display: none;
+ display: none;
}
- #vt100 #reconnect, #vt100 #cursor, #vt100 #menu {
- visibility: hidden;
+ #vt100 #reconnect, #vt100 #cursor, #vt100 #menu, #vt100 #kbd_button, #vt100 #keyboard {
+ visibility: hidden;
}
#vt100 #scrollable {
- overflow: hidden;
+ overflow: hidden;
}
#vt100 #console, #vt100 #alt_console {
- overflow: hidden;
- width: 1000000ex;
+ overflow: hidden;
+ width: 1000000ex;
}
}
this.enableAlternateScreen(false);
var wasCompressed = false;
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter' ];
- for (var i = 0; i < styles.length; ++i) {
- if (typeof this.console[0].style[styles[i]] != 'undefined') {
- for (var j = 0; j < 1; ++j) {
- wasCompressed |= this.console[j].style[styles[i]] != '';
- this.console[j].style[styles[i]] = '';
- }
- this.cursor.style[styles[i]] = '';
- this.space.style[styles[i]] = '';
- if (styles[i] == 'filter') {
- this.console[this.currentScreen].style.width = '';
- }
- break;
+ var transform = this.getTransformName();
+ if (transform) {
+ for (var i = 0; i < 2; ++i) {
+ wasCompressed |= this.console[i].style[transform] != '';
+ this.console[i].style[transform] = '';
+ }
+ this.cursor.style[transform] = '';
+ this.space.style[transform] = '';
+ if (transform == 'filter') {
+ this.console[this.currentScreen].style.width = '';
}
}
this.scale = 1.0;
};
VT100.prototype.addListener = function(elem, event, listener) {
- if (elem.addEventListener) {
- elem.addEventListener(event, listener, false);
- } else {
- elem.attachEvent('on' + event, listener);
+ try {
+ if (elem.addEventListener) {
+ elem.addEventListener(event, listener, false);
+ } else {
+ elem.attachEvent('on' + event, listener);
+ }
+ } catch (e) {
}
};
// Compute hash signature to identify the entries in the userCSS menu.
// If the menu is unchanged from last time, default values can be
// looked up in a cookie associated with this page.
- this.signature = 2;
+ this.signature = 3;
this.utfPreferred = true;
this.visualBell = typeof suppressAllAudio != 'undefined' &&
suppressAllAudio;
this.autoprint = true;
+ this.softKeyboard = false;
this.blinkingCursor = true;
if (this.visualBell) {
this.signature = Math.floor(16807*this.signature + 1) %
if (settings >= 0) {
settings = document.cookie.substr(settings + key.length).
replace(/([0-1]*).*/, "$1");
- if (settings.length == 3 + (typeof userCSSList == 'undefined' ?
+ if (settings.length == 5 + (typeof userCSSList == 'undefined' ?
0 : userCSSList.length)) {
this.utfPreferred = settings.charAt(0) != '0';
this.visualBell = settings.charAt(1) != '0';
this.autoprint = settings.charAt(2) != '0';
- this.blinkingCursor = settings.charAt(3) != '0';
+ this.softKeyboard = settings.charAt(3) != '0';
+ this.blinkingCursor = settings.charAt(4) != '0';
if (typeof userCSSList != 'undefined') {
for (var i = 0; i < userCSSList.length; ++i) {
- userCSSList[i][2] = settings.charAt(i + 3) != '0';
+ userCSSList[i][2] = settings.charAt(i + 5) != '0';
}
}
}
(this.utfEnabled ? '1' : '0') +
(this.visualBell ? '1' : '0') +
(this.autoprint ? '1' : '0') +
+ (this.softKeyboard ? '1' : '0') +
(this.blinkingCursor ? '1' : '0');
if (typeof userCSSList != 'undefined') {
for (var i = 0; i < userCSSList.length; ++i) {
label.textContent= label.textContent;
}
- // User style sheets are number sequentially
+ // User style sheets are numbered sequentially
var sheet = document.getElementById(
'usercss-' + i);
if (i == current) {
}
};
+VT100.prototype.resetLastSelectedKey = function(e) {
+ var key = this.lastSelectedKey;
+ if (!key) {
+ return false;
+ }
+
+ var position = this.mousePosition(e);
+
+ // We don't get all the necessary events to reliably reselect a key
+ // if we moved away from it and then back onto it. We approximate the
+ // behavior by remembering the key until either we release the mouse
+ // button (we might never get this event if the mouse has since left
+ // the window), or until we move away too far.
+ var box = this.keyboard.firstChild;
+ if (position[0] < box.offsetLeft + key.offsetWidth ||
+ position[1] < box.offsetTop + key.offsetHeight ||
+ position[0] >= box.offsetLeft + box.offsetWidth - key.offsetWidth ||
+ position[1] >= box.offsetTop + box.offsetHeight - key.offsetHeight ||
+ position[0] < box.offsetLeft + key.offsetLeft - key.offsetWidth ||
+ position[1] < box.offsetTop + key.offsetTop - key.offsetHeight ||
+ position[0] >= box.offsetLeft + key.offsetLeft + 2*key.offsetWidth ||
+ position[1] >= box.offsetTop + key.offsetTop + 2*key.offsetHeight) {
+ if (this.lastSelectedKey.className) log.console('reset: deselecting');
+ this.lastSelectedKey.className = '';
+ this.lastSelectedKey = undefined;
+ }
+ return false;
+};
+
+VT100.prototype.showShiftState = function(state) {
+ var style = document.getElementById('shift_state');
+ if (state) {
+ this.setTextContentRaw(style,
+ '#vt100 #keyboard .shifted {' +
+ 'display: inline }' +
+ '#vt100 #keyboard .unshifted {' +
+ 'display: none }');
+ } else {
+ this.setTextContentRaw(style, '');
+ }
+ var elems = this.keyboard.getElementsByTagName('I');
+ for (var i = 0; i < elems.length; ++i) {
+ if (elems[i].id == '16') {
+ elems[i].className = state ? 'selected' : '';
+ }
+ }
+};
+
+VT100.prototype.showCtrlState = function(state) {
+ var ctrl = this.getChildById(this.keyboard, '17' /* Ctrl */);
+ if (ctrl) {
+ ctrl.className = state ? 'selected' : '';
+ }
+};
+
+VT100.prototype.showAltState = function(state) {
+ var alt = this.getChildById(this.keyboard, '18' /* Alt */);
+ if (alt) {
+ alt.className = state ? 'selected' : '';
+ }
+};
+
+VT100.prototype.clickedKeyboard = function(e, elem, ch, key, shift, ctrl, alt){
+ var fake = [ ];
+ fake.charCode = ch;
+ fake.keyCode = key;
+ fake.ctrlKey = ctrl;
+ fake.shiftKey = shift;
+ fake.altKey = alt;
+ fake.metaKey = alt;
+ return this.handleKey(fake);
+};
+
+VT100.prototype.addKeyBinding = function(elem, ch, key, CH, KEY) {
+ if (elem == undefined) {
+ return;
+ }
+ if (ch == '\u00A0') {
+ // should be treated as a regular space character.
+ ch = ' ';
+ }
+ if (ch != undefined && CH == undefined) {
+ // For letter keys, we automatically compute the uppercase character code
+ // from the lowercase one.
+ CH = ch.toUpperCase();
+ }
+ if (KEY == undefined && key != undefined) {
+ // Most keys have identically key codes for both lowercase and uppercase
+ // keypresses. Normally, only function keys would have distinct key codes,
+ // whereas regular keys have character codes.
+ KEY = key;
+ } else if (KEY == undefined && CH != undefined) {
+ // For regular keys, copy the character code to the key code.
+ KEY = CH.charCodeAt(0);
+ }
+ if (key == undefined && ch != undefined) {
+ // For regular keys, copy the character code to the key code.
+ key = ch.charCodeAt(0);
+ }
+ // Convert characters to numeric character codes. If the character code
+ // is undefined (i.e. this is a function key), set it to zero.
+ ch = ch ? ch.charCodeAt(0) : 0;
+ CH = CH ? CH.charCodeAt(0) : 0;
+
+ // Mouse down events high light the key. We also set lastSelectedKey. This
+ // is needed to that mouseout/mouseover can keep track of the key that
+ // is currently being clicked.
+ this.addListener(elem, 'mousedown',
+ function(vt100, elem, key) { return function(e) {
+ if ((e.which || e.button) == 1) {
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className= '';
+ }
+ // Highlight the key while the mouse button is held down.
+ if (key == 16 /* Shift */) {
+ if (!elem.className != vt100.isShift) {
+ vt100.showShiftState(!vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className != vt100.isCtrl) {
+ vt100.showCtrlState(!vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className != vt100.isAlt) {
+ vt100.showAltState(!vt100.isAlt);
+ }
+ } else {
+ elem.className = 'selected';
+ }
+ vt100.lastSelectedKey = elem;
+ }
+ return false; }; }(this, elem, key));
+ var clicked =
+ // Modifier keys update the state of the keyboard, but do not generate
+ // any key clicks that get forwarded to the application.
+ key >= 16 /* Shift */ && key <= 18 /* Alt */ ?
+ function(vt100, elem) { return function(e) {
+ if (elem == vt100.lastSelectedKey) {
+ if (key == 16 /* Shift */) {
+ // The user clicked the Shift key
+ vt100.isShift = !vt100.isShift;
+ vt100.showShiftState(vt100.isShift);
+ } else if (key == 17 /* Ctrl */) {
+ vt100.isCtrl = !vt100.isCtrl;
+ vt100.showCtrlState(vt100.isCtrl);
+ } else if (key == 18 /* Alt */) {
+ vt100.isAlt = !vt100.isAlt;
+ vt100.showAltState(vt100.isAlt);
+ }
+ vt100.lastSelectedKey = undefined;
+ }
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ return false; }; }(this, elem) :
+ // Regular keys generate key clicks, when the mouse button is released or
+ // when a mouse click event is received.
+ function(vt100, elem, ch, key, CH, KEY) { return function(e) {
+ if (vt100.lastSelectedKey) {
+ if (elem == vt100.lastSelectedKey) {
+ // The user clicked a key.
+ if (vt100.isShift) {
+ vt100.clickedKeyboard(e, elem, CH, KEY,
+ true, vt100.isCtrl, vt100.isAlt);
+ } else {
+ vt100.clickedKeyboard(e, elem, ch, key,
+ false, vt100.isCtrl, vt100.isAlt);
+ }
+ vt100.isShift = false;
+ vt100.showShiftState(false);
+ vt100.isCtrl = false;
+ vt100.showCtrlState(false);
+ vt100.isAlt = false;
+ vt100.showAltState(false);
+ }
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ elem.className = '';
+ return false; }; }(this, elem, ch, key, CH, KEY);
+ this.addListener(elem, 'mouseup', clicked);
+ this.addListener(elem, 'click', clicked);
+
+ // When moving the mouse away from a key, check if any keys need to be
+ // deselected.
+ this.addListener(elem, 'mouseout',
+ function(vt100, elem, key) { return function(e) {
+ if (key == 16 /* Shift */) {
+ if (!elem.className == vt100.isShift) {
+ vt100.showShiftState(vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className == vt100.isCtrl) {
+ vt100.showCtrlState(vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className == vt100.isAlt) {
+ vt100.showAltState(vt100.isAlt);
+ }
+ } else if (elem.className) {
+ elem.className = '';
+ vt100.lastSelectedKey = elem;
+ } else if (vt100.lastSelectedKey) {
+ vt100.resetLastSelectedKey(e);
+ }
+ return false; }; }(this, elem, key));
+
+ // When moving the mouse over a key, select it if the user is still holding
+ // the mouse button down (i.e. elem == lastSelectedKey)
+ this.addListener(elem, 'mouseover',
+ function(vt100, elem, key) { return function(e) {
+ if (elem == vt100.lastSelectedKey) {
+ if (key == 16 /* Shift */) {
+ if (!elem.className != vt100.isShift) {
+ vt100.showShiftState(!vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className != vt100.isCtrl) {
+ vt100.showCtrlState(!vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className != vt100.isAlt) {
+ vt100.showAltState(!vt100.isAlt);
+ }
+ } else if (!elem.className) {
+ elem.className = 'selected';
+ }
+ } else {
+ vt100.resetLastSelectedKey(e);
+ }
+ return false; }; }(this, elem, key));
+};
+
+VT100.prototype.initializeKeyBindings = function(elem) {
+ if (elem) {
+ if (elem.nodeName == "I" || elem.nodeName == "B") {
+ if (elem.id) {
+ // Function keys. The Javascript keycode is part of the "id"
+ var i = parseInt(elem.id);
+ if (i) {
+ // If the id does not parse as a number, it is not a keycode.
+ this.addKeyBinding(elem, undefined, i);
+ }
+ } else {
+ var child = elem.firstChild;
+ if (child.nodeName == "#text") {
+ // If the key only has a text node as a child, then it is a letter.
+ // Automatically compute the lower and upper case version of the key.
+ this.addKeyBinding(elem, this.getTextContent(child).toLowerCase());
+ } else {
+ // If the key has two children, they are the lower and upper case
+ // character code, respectively.
+ this.addKeyBinding(elem, this.getTextContent(child), undefined,
+ this.getTextContent(child.nextSibling));
+ }
+ }
+ }
+ }
+ // Recursively parse all other child nodes.
+ for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ this.initializeKeyBindings(elem);
+ }
+};
+
+VT100.prototype.initializeKeyboard = function() {
+ // Configure mouse event handlers for button that displays/hides keyboard
+ var box = this.keyboard.firstChild;
+ this.hideSoftKeyboard();
+ this.addListener(this.keyboardImage, 'click',
+ function(vt100) { return function(e) {
+ if (vt100.keyboard.style.display != '') {
+ if (vt100.reconnectBtn.style.visibility != '') {
+ vt100.showSoftKeyboard();
+ }
+ } else {
+ vt100.hideSoftKeyboard();
+ vt100.input.focus();
+ }
+ return false; }; }(this));
+
+ // Enable button that displays keyboard
+ if (this.softKeyboard) {
+ this.keyboardImage.style.visibility = 'visible';
+ }
+
+ // Configure mouse event handlers for on-screen keyboard
+ this.addListener(this.keyboard, 'click',
+ function(vt100) { return function(e) {
+ vt100.hideSoftKeyboard();
+ vt100.input.focus();
+ return false; }; }(this));
+ this.addListener(this.keyboard, 'selectstart', this.cancelEvent);
+ this.addListener(box, 'click', this.cancelEvent);
+ this.addListener(box, 'mouseup',
+ function(vt100) { return function(e) {
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ return false; }; }(this));
+ this.addListener(box, 'mouseout',
+ function(vt100) { return function(e) {
+ return vt100.resetLastSelectedKey(e); }; }(this));
+ this.addListener(box, 'mouseover',
+ function(vt100) { return function(e) {
+ return vt100.resetLastSelectedKey(e); }; }(this));
+
+ // Configure SHIFT key behavior
+ var style = document.createElement('style');
+ var id = document.createAttribute('id');
+ id.nodeValue = 'shift_state';
+ style.setAttributeNode(id);
+ var type = document.createAttribute('type');
+ type.nodeValue = 'text/css';
+ style.setAttributeNode(type);
+ document.getElementsByTagName('head')[0].appendChild(style);
+
+ // Set up key bindings
+ this.initializeKeyBindings(box);
+};
+
VT100.prototype.initializeElements = function(container) {
// If the necessary objects have not already been defined in the HTML
// page, create them now.
if (!this.getChildById(this.container, 'reconnect') ||
!this.getChildById(this.container, 'menu') ||
+ !this.getChildById(this.container, 'keyboard') ||
+ !this.getChildById(this.container, 'kbd_button') ||
+ !this.getChildById(this.container, 'kbd_img') ||
!this.getChildById(this.container, 'scrollable') ||
!this.getChildById(this.container, 'console') ||
!this.getChildById(this.container, 'alt_console') ||
'<div id="cursize" style="visibility: hidden">' +
'</div>' +
'<div id="menu"></div>' +
+ '<div id="keyboard" unselectable="on">' +
+ '<pre class="box"><div><i id="27">Esc</i><i id="112">F1</i><i id="113">F2</i><i id="114">F3</i><i id="115">F4</i><i id="116">F5</i><i id="117">F6</i><i id="118">F7</i><i id="119">F8</i><i id="120">F9</i><i id="121">F10</i><i id="122">F11</i><i id="123">F12</i><br /><b><span class="unshifted">`</span><span class="shifted">~</span></b><b><span class="unshifted">1</span><span class="shifted">!</span></b><b><span class="unshifted">2</span><span class="shifted">@</span></b><b><span class="unshifted">3</span><span class="shifted">#</span></b><b><span class="unshifted">4</span><span class="shifted">$</span></b><b><span class="unshifted">5</span><span class="shifted">%</span></b><b><span class="unshifted">6</span><span class="shifted">^</span></b><b><span class="unshifted">7</span><span class="shifted">&</span></b><b><span class="unshifted">8</span><span class="shifted">*</span></b><b><span class="unshifted">9</span><span class="shifted">(</span></b><b><span class="unshifted">0</span><span class="shifted">)</span></b><b><span class="unshifted">-</span><span class="shifted">_</span></b><b><span class="unshifted">=</span><span class="shifted">+</span></b><i id="8"> ← </i><br /><i id="9">Tab</i><b>Q</b><b>W</b><b>E</b><b>R</b><b>T</b><b>Y</b><b>U</b><b>I</b><b>O</b><b>P</b><b><span class="unshifted">[</span><span class="shifted">{</span></b><b><span class="unshifted">]</span><span class="shifted">}</span></b><b><span class="unshifted">\</span><span class="shifted">|</span></b><br /><u>Tab </u><b>A</b><b>S</b><b>D</b><b>F</b><b>G</b><b>H</b><b>J</b><b>K</b><b>L</b><b><span class="unshifted">;</span><span class="shifted">:</span></b><b><span class="unshifted">'</span><span class="shifted">"</span></b><i id="13">Enter</i><br /><u> </u><i id="16">Shift</i><b>Z</b><b>X</b><b>C</b><b>V</b><b>B</b><b>N</b><b>M</b><b><span class="unshifted">,</span><span class="shifted"><</span></b><b><span class="unshifted">.</span><span class="shifted">></span></b><b><span class="unshifted">/</span><span class="shifted">?</span></b><i id="16">Shift</i><br /><u>XXX</u><i id="17">Ctrl</i><i id="18">Alt</i><i style="width: 25ex"> </i></div> <div><i id="45">Ins</i><i id="46">Del</i><i id="36">Home</i><i id="35">End</i><br /><u> </u><br /><u> </u><br /><u>Ins</u><s> </s><b id="38">↑</b><s> </s><u> </u><b id="33">⇑</b><br /><u>Ins</u><b id="37">←</b><b id="40">↓</b><b id="39">→</b><u> </u><b id="34">⇓</b></div></pre>' +
+ '</div>' +
'<div id="scrollable">' +
+ '<table id="kbd_button">' +
+ '<tr><td width="100%"> </td>' +
+ '<td><img id="kbd_img" src="keyboard.png" /></td>' +
+ '<td> </td></tr>' +
+ '</table>' +
'<pre id="lineheight"> </pre>' +
'<pre id="console">' +
'<pre></pre>' +
this.reconnectBtn = this.getChildById(this.container,'reconnect');
this.curSizeBox = this.getChildById(this.container, 'cursize');
this.menu = this.getChildById(this.container, 'menu');
+ this.keyboard = this.getChildById(this.container, 'keyboard');
+ this.keyboardImage = this.getChildById(this.container, 'kbd_img');
this.scrollable = this.getChildById(this.container,
'scrollable');
this.lineheight = this.getChildById(this.container,
// Hide context menu
this.hideContextMenu();
+ // Set up onscreen soft keyboard
+ this.initializeKeyboard();
+
// Add listener to reconnect button
this.addListener(this.reconnectBtn.firstChild, 'click',
function(vt100) {
VT100.prototype.showReconnect = function(state) {
if (state) {
+ this.hideSoftKeyboard();
this.reconnectBtn.style.visibility = '';
} else {
this.reconnectBtn.style.visibility = 'hidden';
};
VT100.prototype.resizer = function() {
+ // Hide onscreen soft keyboard
+ this.hideSoftKeyboard();
+
// The cursor can get corrupted if the print-preview is displayed in Firefox.
// Recreating it, will repair it.
var newCursor = document.createElement('pre');
return false;
};
+VT100.prototype.mousePosition = function(event) {
+ var offsetX = this.container.offsetLeft;
+ var offsetY = this.container.offsetTop;
+ for (var e = this.container; e = e.offsetParent; ) {
+ offsetX += e.offsetLeft;
+ offsetY += e.offsetTop;
+ }
+ return [ event.clientX - offsetX,
+ event.clientY - offsetY ];
+};
+
VT100.prototype.mouseEvent = function(event, type) {
// If any text is currently selected, do not move the focus as that would
// invalidate the selection.
}
// Compute mouse position in characters.
- var offsetX = this.container.offsetLeft;
- var offsetY = this.container.offsetTop;
- for (var e = this.container; e = e.offsetParent; ) {
- offsetX += e.offsetLeft;
- offsetY += e.offsetTop;
- }
- var x = (event.clientX - offsetX) / this.cursorWidth;
- var y = ((event.clientY - offsetY) + this.scrollable.offsetTop) /
- this.cursorHeight - this.numScrollbackLines;
+ var position = this.mousePosition(event);
+ var x = Math.floor(position[0] / this.cursorWidth);
+ var y = Math.floor((position[1] + this.scrollable.scrollTop) /
+ this.cursorHeight) - this.numScrollbackLines;
var inside = true;
if (x >= this.terminalWidth) {
x = this.terminalWidth - 1;
// Bring up context menu.
if (button == 2 && !event.shiftKey) {
if (type == 0 /* MOUSE_DOWN */) {
- this.showContextMenu(event.clientX - offsetX, event.clientY - offsetY);
+ this.showContextMenu(position[0], position[1]);
}
return this.cancelEvent(event);
}
(typeof elem.textContent == 'undefined' ? elem.innerText : '');
};
+VT100.prototype.setTextContentRaw = function(elem, s) {
+ // Updating the content of an element is an expensive operation. It actually
+ // pays off to first check whether the element is still unchanged.
+ if (typeof elem.textContent == 'undefined') {
+ if (elem.innerText != s) {
+ try {
+ elem.innerText = s;
+ } catch (e) {
+ // Very old versions of IE do not allow setting innerText. Instead,
+ // remove all children, by setting innerHTML and then set the text
+ // using DOM methods.
+ elem.innerHTML = '';
+ elem.appendChild(document.createTextNode(
+ this.replaceChar(s, ' ', '\u00A0')));
+ }
+ }
+ } else {
+ if (elem.textContent != s) {
+ elem.textContent = s;
+ }
+ }
+};
+
VT100.prototype.setTextContent = function(elem, s) {
// Check if we find any URLs in the text. If so, automatically convert them
// to links.
return;
}
- // Updating the content of an element is an expensive operation. It actually
- // pays off to first check whether the element is still unchanged.
- if (typeof elem.textContent == 'undefined') {
- if (elem.innerText != s) {
- try {
- elem.innerText = s;
- } catch (e) {
- // Very old versions of IE do not allow setting innerText. Instead,
- // remove all children, by setting innerHTML and then set the text
- // using DOM methods.
- elem.innerHTML = '';
- elem.appendChild(document.createTextNode(
- this.replaceChar(s, ' ', '\u00A0')));
- }
- }
- } else {
- if (elem.textContent != s) {
- elem.textContent = s;
- }
- }
+ this.setTextContentRaw(elem, s);
};
VT100.prototype.insertBlankLine = function(y, color, style) {
this.console[this.currentScreen].style.display = '';
// Select appropriate character pitch.
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter' ];
- for (var i = 0; i < styles.length; ++i) {
- if (typeof this.console[0].style[styles[i]] != 'undefined') {
- if (state) {
- // Upon enabling the alternate screen, we switch to 80 column mode. But
- // upon returning to the regular screen, we restore the mode that was
- // in effect previously.
- this.console[1].style[styles[i]] = '';
- }
- var style =
- this.console[this.currentScreen].style[styles[i]];
- this.cursor.style[styles[i]] = style;
- this.space.style[styles[i]] = style;
- this.scale = style == '' ? 1.0:1.65;
- if (styles[i] == 'filter') {
- this.console[this.currentScreen].style.width = style == '' ? '165%':'';
- }
- break;
+ var transform = this.getTransformName();
+ if (transform) {
+ if (state) {
+ // Upon enabling the alternate screen, we switch to 80 column mode. But
+ // upon returning to the regular screen, we restore the mode that was
+ // in effect previously.
+ this.console[1].style[transform] = '';
+ }
+ var style =
+ this.console[this.currentScreen].style[transform];
+ this.cursor.style[transform] = style;
+ this.space.style[transform] = style;
+ this.scale = style == '' ? 1.0:1.65;
+ if (transform == 'filter') {
+ this.console[this.currentScreen].style.width = style == '' ? '165%':'';
}
}
this.resizer();
this.visualBell = !this.visualBell;
};
+VT100.prototype.toggleSoftKeyboard = function() {
+ this.softKeyboard = !this.softKeyboard;
+ this.keyboardImage.style.visibility = this.softKeyboard ? 'visible' : '';
+};
+
+VT100.prototype.deselectKeys = function(elem) {
+ if (elem && elem.className == 'selected') {
+ elem.className = '';
+ }
+ for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ this.deselectKeys(elem);
+ }
+};
+
+VT100.prototype.showSoftKeyboard = function() {
+ // Make sure no key is currently selected
+ this.lastSelectedKey = undefined;
+ this.deselectKeys(this.keyboard);
+ this.isShift = false;
+ this.showShiftState(false);
+ this.isCtrl = false;
+ this.showCtrlState(false);
+ this.isAlt = false;
+ this.showAltState(false);
+
+ this.keyboard.style.left = '0px';
+ this.keyboard.style.top = '0px';
+ this.keyboard.style.width = this.container.offsetWidth + 'px';
+ this.keyboard.style.height = this.container.offsetHeight + 'px';
+ this.keyboard.style.visibility = 'hidden';
+ this.keyboard.style.display = '';
+
+ var kbd = this.keyboard.firstChild;
+ var scale = 1.0;
+ var transform = this.getTransformName();
+ if (transform) {
+ kbd.style[transform] = '';
+ if (kbd.offsetWidth > 0.9 * this.container.offsetWidth) {
+ scale = (kbd.offsetWidth/
+ this.container.offsetWidth)/0.9;
+ }
+ if (kbd.offsetHeight > 0.9 * this.container.offsetHeight) {
+ scale = Math.max((kbd.offsetHeight/
+ this.container.offsetHeight)/0.9);
+ }
+ var style = this.getTransformStyle(transform,
+ scale > 1.0 ? scale : undefined);
+ kbd.style[transform] = style;
+ }
+ if (transform == 'filter') {
+ scale = 1.0;
+ }
+ kbd.style.left = ((this.container.offsetWidth -
+ kbd.offsetWidth/scale)/2) + 'px';
+ kbd.style.top = ((this.container.offsetHeight -
+ kbd.offsetHeight/scale)/2) + 'px';
+
+ this.keyboard.style.visibility = 'visible';
+};
+
+VT100.prototype.hideSoftKeyboard = function() {
+ this.keyboard.style.display = 'none';
+};
+
VT100.prototype.toggleCursorBlinking = function() {
this.blinkingCursor = !this.blinkingCursor;
};
VT100.prototype.about = function() {
- alert("VT100 Terminal Emulator " + "2.10 (revision 220)" +
+ alert("VT100 Terminal Emulator " + "2.10 (revision 221)" +
"\nCopyright 2008-2010 by Markus Gutschke\n" +
"For more information check http://shellinabox.com");
};
'<li>' +
(this.visualBell ? '<img src="enabled.gif" />' : '') +
'Visual Bell</li>'+
+ '<li>' +
+ (this.softKeyboard ? '<img src="enabled.gif" />' : '') +
+ 'Onscreen Keyboard</li>' +
'<li id="endconfig">' +
(this.blinkingCursor ? '<img src="enabled.gif" />' : '') +
'Blinking Cursor</li>'+
// Actions for default items
var actions = [ this.copyLast, p, this.reset,
this.toggleUTF, this.toggleBell,
+ this.toggleSoftKeyboard,
this.toggleCursorBlinking ];
// Actions for user CSS styles (if any)
}
// Position menu next to the mouse pointer
- if (x + popup.clientWidth > this.container.offsetWidth) {
- x = this.container.offsetWidth - popup.clientWidth;
+ this.menu.style.left = '0px';
+ this.menu.style.top = '0px';
+ this.menu.style.width = this.container.offsetWidth + 'px';
+ this.menu.style.height = this.container.offsetHeight + 'px';
+ popup.style.left = '0px';
+ popup.style.top = '0px';
+
+ var margin = 2;
+ if (x + popup.clientWidth >= this.container.offsetWidth - margin) {
+ x = this.container.offsetWidth-popup.clientWidth - margin - 1;
}
- if (x < 0) {
- x = 0;
+ if (x < margin) {
+ x = margin;
}
- if (y + popup.clientHeight > this.container.offsetHeight) {
- y = this.container.offsetHeight-popup.clientHeight;
+ if (y + popup.clientHeight >= this.container.offsetHeight - margin) {
+ y = this.container.offsetHeight-popup.clientHeight - margin - 1;
}
- if (y < 0) {
- y = 0;
+ if (y < margin) {
+ y = margin;
}
popup.style.left = x + 'px';
popup.style.top = y + 'px';
// Block all other interactions with the terminal emulator
- this.menu.style.left = '0px';
- this.menu.style.top = '0px';
- this.menu.style.width = this.container.offsetWidth + 'px';
- this.menu.style.height = this.container.offsetHeight + 'px';
this.addListener(this.menu, 'click', function(vt100) {
return function() {
vt100.hideContextMenu();
this.savedY[this.currentScreen]);
};
-VT100.prototype.set80_132Mode = function(state) {
- var transform = undefined;
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter'
- ];
+VT100.prototype.getTransformName = function() {
+ var styles = [ 'transform', 'WebkitTransform', 'MozTransform', 'filter' ];
for (var i = 0; i < styles.length; ++i) {
if (typeof this.console[0].style[styles[i]] != 'undefined') {
- transform = styles[i];
- break;
+ return styles[i];
}
}
+ return undefined;
+};
+VT100.prototype.getTransformStyle = function(transform, scale) {
+ return scale && scale != 1.0
+ ? transform == 'filter'
+ ? 'progid:DXImageTransform.Microsoft.Matrix(' +
+ 'M11=' + (1.0/scale) + ',M12=0,M21=0,M22=1,' +
+ "sizingMethod='auto expand')"
+ : 'translateX(-50%) ' +
+ 'scaleX(' + (1.0/scale) + ') ' +
+ 'translateX(50%)'
+ : '';
+};
+
+VT100.prototype.set80_132Mode = function(state) {
+ var transform = this.getTransformName();
if (transform) {
if ((this.console[this.currentScreen].style[transform] != '') == state) {
return;
}
- var style =
- state ? transform == 'filter'
- ? 'progid:DXImageTransform.Microsoft.Matrix(' +
- 'M11=0.606060606060606060606,M12=0,M21=0,M22=1,' +
- "sizingMethod='auto expand')"
- : 'translateX(-50%) ' +
- 'scaleX(0.606060606060606060606) ' +
- 'translateX(50%)'
- : '';
+ var style = state ?
+ this.getTransformStyle(transform, 1.65):'';
this.console[this.currentScreen].style[transform] = style;
- this.cursor.style[transform] = style;
- this.space.style[transform] = style;
- this.scale = state ? 1.65 : 1.0;
+ this.cursor.style[transform] = style;
+ this.space.style[transform] = style;
+ this.scale = state ? 1.65 : 1.0;
if (transform == 'filter') {
- this.console[this.currentScreen].style.width = state ? '165%' : '';
+ this.console[this.currentScreen].style.width = state ? '165%' : '';
}
this.resizer();
}
this.enableAlternateScreen(false);
var wasCompressed = false;
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter' ];
- for (var i = 0; i < styles.length; ++i) {
- if (typeof this.console[0].style[styles[i]] != 'undefined') {
- for (var j = 0; j < 1; ++j) {
- wasCompressed |= this.console[j].style[styles[i]] != '';
- this.console[j].style[styles[i]] = '';
- }
- this.cursor.style[styles[i]] = '';
- this.space.style[styles[i]] = '';
- if (styles[i] == 'filter') {
- this.console[this.currentScreen].style.width = '';
- }
- break;
+ var transform = this.getTransformName();
+ if (transform) {
+ for (var i = 0; i < 2; ++i) {
+ wasCompressed |= this.console[i].style[transform] != '';
+ this.console[i].style[transform] = '';
+ }
+ this.cursor.style[transform] = '';
+ this.space.style[transform] = '';
+ if (transform == 'filter') {
+ this.console[this.currentScreen].style.width = '';
}
}
this.scale = 1.0;
};
VT100.prototype.addListener = function(elem, event, listener) {
- if (elem.addEventListener) {
- elem.addEventListener(event, listener, false);
- } else {
- elem.attachEvent('on' + event, listener);
+ try {
+ if (elem.addEventListener) {
+ elem.addEventListener(event, listener, false);
+ } else {
+ elem.attachEvent('on' + event, listener);
+ }
+ } catch (e) {
}
};
// Compute hash signature to identify the entries in the userCSS menu.
// If the menu is unchanged from last time, default values can be
// looked up in a cookie associated with this page.
- this.signature = 2;
+ this.signature = 3;
this.utfPreferred = true;
this.visualBell = typeof suppressAllAudio != 'undefined' &&
suppressAllAudio;
this.autoprint = true;
+ this.softKeyboard = false;
this.blinkingCursor = true;
if (this.visualBell) {
this.signature = Math.floor(16807*this.signature + 1) %
if (settings >= 0) {
settings = document.cookie.substr(settings + key.length).
replace(/([0-1]*).*/, "$1");
- if (settings.length == 3 + (typeof userCSSList == 'undefined' ?
+ if (settings.length == 5 + (typeof userCSSList == 'undefined' ?
0 : userCSSList.length)) {
this.utfPreferred = settings.charAt(0) != '0';
this.visualBell = settings.charAt(1) != '0';
this.autoprint = settings.charAt(2) != '0';
- this.blinkingCursor = settings.charAt(3) != '0';
+ this.softKeyboard = settings.charAt(3) != '0';
+ this.blinkingCursor = settings.charAt(4) != '0';
if (typeof userCSSList != 'undefined') {
for (var i = 0; i < userCSSList.length; ++i) {
- userCSSList[i][2] = settings.charAt(i + 3) != '0';
+ userCSSList[i][2] = settings.charAt(i + 5) != '0';
}
}
}
(this.utfEnabled ? '1' : '0') +
(this.visualBell ? '1' : '0') +
(this.autoprint ? '1' : '0') +
+ (this.softKeyboard ? '1' : '0') +
(this.blinkingCursor ? '1' : '0');
if (typeof userCSSList != 'undefined') {
for (var i = 0; i < userCSSList.length; ++i) {
label.textContent= label.textContent;
}
- // User style sheets are number sequentially
+ // User style sheets are numbered sequentially
var sheet = document.getElementById(
'usercss-' + i);
if (i == current) {
}
};
+VT100.prototype.resetLastSelectedKey = function(e) {
+ var key = this.lastSelectedKey;
+ if (!key) {
+ return false;
+ }
+
+ var position = this.mousePosition(e);
+
+ // We don't get all the necessary events to reliably reselect a key
+ // if we moved away from it and then back onto it. We approximate the
+ // behavior by remembering the key until either we release the mouse
+ // button (we might never get this event if the mouse has since left
+ // the window), or until we move away too far.
+ var box = this.keyboard.firstChild;
+ if (position[0] < box.offsetLeft + key.offsetWidth ||
+ position[1] < box.offsetTop + key.offsetHeight ||
+ position[0] >= box.offsetLeft + box.offsetWidth - key.offsetWidth ||
+ position[1] >= box.offsetTop + box.offsetHeight - key.offsetHeight ||
+ position[0] < box.offsetLeft + key.offsetLeft - key.offsetWidth ||
+ position[1] < box.offsetTop + key.offsetTop - key.offsetHeight ||
+ position[0] >= box.offsetLeft + key.offsetLeft + 2*key.offsetWidth ||
+ position[1] >= box.offsetTop + key.offsetTop + 2*key.offsetHeight) {
+ if (this.lastSelectedKey.className) log.console('reset: deselecting');
+ this.lastSelectedKey.className = '';
+ this.lastSelectedKey = undefined;
+ }
+ return false;
+};
+
+VT100.prototype.showShiftState = function(state) {
+ var style = document.getElementById('shift_state');
+ if (state) {
+ this.setTextContentRaw(style,
+ '#vt100 #keyboard .shifted {' +
+ 'display: inline }' +
+ '#vt100 #keyboard .unshifted {' +
+ 'display: none }');
+ } else {
+ this.setTextContentRaw(style, '');
+ }
+ var elems = this.keyboard.getElementsByTagName('I');
+ for (var i = 0; i < elems.length; ++i) {
+ if (elems[i].id == '16') {
+ elems[i].className = state ? 'selected' : '';
+ }
+ }
+};
+
+VT100.prototype.showCtrlState = function(state) {
+ var ctrl = this.getChildById(this.keyboard, '17' /* Ctrl */);
+ if (ctrl) {
+ ctrl.className = state ? 'selected' : '';
+ }
+};
+
+VT100.prototype.showAltState = function(state) {
+ var alt = this.getChildById(this.keyboard, '18' /* Alt */);
+ if (alt) {
+ alt.className = state ? 'selected' : '';
+ }
+};
+
+VT100.prototype.clickedKeyboard = function(e, elem, ch, key, shift, ctrl, alt){
+ var fake = [ ];
+ fake.charCode = ch;
+ fake.keyCode = key;
+ fake.ctrlKey = ctrl;
+ fake.shiftKey = shift;
+ fake.altKey = alt;
+ fake.metaKey = alt;
+ return this.handleKey(fake);
+};
+
+VT100.prototype.addKeyBinding = function(elem, ch, key, CH, KEY) {
+ if (elem == undefined) {
+ return;
+ }
+ if (ch == '\u00A0') {
+ // should be treated as a regular space character.
+ ch = ' ';
+ }
+ if (ch != undefined && CH == undefined) {
+ // For letter keys, we automatically compute the uppercase character code
+ // from the lowercase one.
+ CH = ch.toUpperCase();
+ }
+ if (KEY == undefined && key != undefined) {
+ // Most keys have identically key codes for both lowercase and uppercase
+ // keypresses. Normally, only function keys would have distinct key codes,
+ // whereas regular keys have character codes.
+ KEY = key;
+ } else if (KEY == undefined && CH != undefined) {
+ // For regular keys, copy the character code to the key code.
+ KEY = CH.charCodeAt(0);
+ }
+ if (key == undefined && ch != undefined) {
+ // For regular keys, copy the character code to the key code.
+ key = ch.charCodeAt(0);
+ }
+ // Convert characters to numeric character codes. If the character code
+ // is undefined (i.e. this is a function key), set it to zero.
+ ch = ch ? ch.charCodeAt(0) : 0;
+ CH = CH ? CH.charCodeAt(0) : 0;
+
+ // Mouse down events high light the key. We also set lastSelectedKey. This
+ // is needed to that mouseout/mouseover can keep track of the key that
+ // is currently being clicked.
+ this.addListener(elem, 'mousedown',
+ function(vt100, elem, key) { return function(e) {
+ if ((e.which || e.button) == 1) {
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className= '';
+ }
+ // Highlight the key while the mouse button is held down.
+ if (key == 16 /* Shift */) {
+ if (!elem.className != vt100.isShift) {
+ vt100.showShiftState(!vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className != vt100.isCtrl) {
+ vt100.showCtrlState(!vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className != vt100.isAlt) {
+ vt100.showAltState(!vt100.isAlt);
+ }
+ } else {
+ elem.className = 'selected';
+ }
+ vt100.lastSelectedKey = elem;
+ }
+ return false; }; }(this, elem, key));
+ var clicked =
+ // Modifier keys update the state of the keyboard, but do not generate
+ // any key clicks that get forwarded to the application.
+ key >= 16 /* Shift */ && key <= 18 /* Alt */ ?
+ function(vt100, elem) { return function(e) {
+ if (elem == vt100.lastSelectedKey) {
+ if (key == 16 /* Shift */) {
+ // The user clicked the Shift key
+ vt100.isShift = !vt100.isShift;
+ vt100.showShiftState(vt100.isShift);
+ } else if (key == 17 /* Ctrl */) {
+ vt100.isCtrl = !vt100.isCtrl;
+ vt100.showCtrlState(vt100.isCtrl);
+ } else if (key == 18 /* Alt */) {
+ vt100.isAlt = !vt100.isAlt;
+ vt100.showAltState(vt100.isAlt);
+ }
+ vt100.lastSelectedKey = undefined;
+ }
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ return false; }; }(this, elem) :
+ // Regular keys generate key clicks, when the mouse button is released or
+ // when a mouse click event is received.
+ function(vt100, elem, ch, key, CH, KEY) { return function(e) {
+ if (vt100.lastSelectedKey) {
+ if (elem == vt100.lastSelectedKey) {
+ // The user clicked a key.
+ if (vt100.isShift) {
+ vt100.clickedKeyboard(e, elem, CH, KEY,
+ true, vt100.isCtrl, vt100.isAlt);
+ } else {
+ vt100.clickedKeyboard(e, elem, ch, key,
+ false, vt100.isCtrl, vt100.isAlt);
+ }
+ vt100.isShift = false;
+ vt100.showShiftState(false);
+ vt100.isCtrl = false;
+ vt100.showCtrlState(false);
+ vt100.isAlt = false;
+ vt100.showAltState(false);
+ }
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ elem.className = '';
+ return false; }; }(this, elem, ch, key, CH, KEY);
+ this.addListener(elem, 'mouseup', clicked);
+ this.addListener(elem, 'click', clicked);
+
+ // When moving the mouse away from a key, check if any keys need to be
+ // deselected.
+ this.addListener(elem, 'mouseout',
+ function(vt100, elem, key) { return function(e) {
+ if (key == 16 /* Shift */) {
+ if (!elem.className == vt100.isShift) {
+ vt100.showShiftState(vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className == vt100.isCtrl) {
+ vt100.showCtrlState(vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className == vt100.isAlt) {
+ vt100.showAltState(vt100.isAlt);
+ }
+ } else if (elem.className) {
+ elem.className = '';
+ vt100.lastSelectedKey = elem;
+ } else if (vt100.lastSelectedKey) {
+ vt100.resetLastSelectedKey(e);
+ }
+ return false; }; }(this, elem, key));
+
+ // When moving the mouse over a key, select it if the user is still holding
+ // the mouse button down (i.e. elem == lastSelectedKey)
+ this.addListener(elem, 'mouseover',
+ function(vt100, elem, key) { return function(e) {
+ if (elem == vt100.lastSelectedKey) {
+ if (key == 16 /* Shift */) {
+ if (!elem.className != vt100.isShift) {
+ vt100.showShiftState(!vt100.isShift);
+ }
+ } else if (key == 17 /* Ctrl */) {
+ if (!elem.className != vt100.isCtrl) {
+ vt100.showCtrlState(!vt100.isCtrl);
+ }
+ } else if (key == 18 /* Alt */) {
+ if (!elem.className != vt100.isAlt) {
+ vt100.showAltState(!vt100.isAlt);
+ }
+ } else if (!elem.className) {
+ elem.className = 'selected';
+ }
+ } else {
+ vt100.resetLastSelectedKey(e);
+ }
+ return false; }; }(this, elem, key));
+};
+
+VT100.prototype.initializeKeyBindings = function(elem) {
+ if (elem) {
+ if (elem.nodeName == "I" || elem.nodeName == "B") {
+ if (elem.id) {
+ // Function keys. The Javascript keycode is part of the "id"
+ var i = parseInt(elem.id);
+ if (i) {
+ // If the id does not parse as a number, it is not a keycode.
+ this.addKeyBinding(elem, undefined, i);
+ }
+ } else {
+ var child = elem.firstChild;
+ if (child.nodeName == "#text") {
+ // If the key only has a text node as a child, then it is a letter.
+ // Automatically compute the lower and upper case version of the key.
+ this.addKeyBinding(elem, this.getTextContent(child).toLowerCase());
+ } else {
+ // If the key has two children, they are the lower and upper case
+ // character code, respectively.
+ this.addKeyBinding(elem, this.getTextContent(child), undefined,
+ this.getTextContent(child.nextSibling));
+ }
+ }
+ }
+ }
+ // Recursively parse all other child nodes.
+ for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ this.initializeKeyBindings(elem);
+ }
+};
+
+VT100.prototype.initializeKeyboard = function() {
+ // Configure mouse event handlers for button that displays/hides keyboard
+ var box = this.keyboard.firstChild;
+ this.hideSoftKeyboard();
+ this.addListener(this.keyboardImage, 'click',
+ function(vt100) { return function(e) {
+ if (vt100.keyboard.style.display != '') {
+ if (vt100.reconnectBtn.style.visibility != '') {
+ vt100.showSoftKeyboard();
+ }
+ } else {
+ vt100.hideSoftKeyboard();
+ vt100.input.focus();
+ }
+ return false; }; }(this));
+
+ // Enable button that displays keyboard
+ if (this.softKeyboard) {
+ this.keyboardImage.style.visibility = 'visible';
+ }
+
+ // Configure mouse event handlers for on-screen keyboard
+ this.addListener(this.keyboard, 'click',
+ function(vt100) { return function(e) {
+ vt100.hideSoftKeyboard();
+ vt100.input.focus();
+ return false; }; }(this));
+ this.addListener(this.keyboard, 'selectstart', this.cancelEvent);
+ this.addListener(box, 'click', this.cancelEvent);
+ this.addListener(box, 'mouseup',
+ function(vt100) { return function(e) {
+ if (vt100.lastSelectedKey) {
+ vt100.lastSelectedKey.className = '';
+ vt100.lastSelectedKey = undefined;
+ }
+ return false; }; }(this));
+ this.addListener(box, 'mouseout',
+ function(vt100) { return function(e) {
+ return vt100.resetLastSelectedKey(e); }; }(this));
+ this.addListener(box, 'mouseover',
+ function(vt100) { return function(e) {
+ return vt100.resetLastSelectedKey(e); }; }(this));
+
+ // Configure SHIFT key behavior
+ var style = document.createElement('style');
+ var id = document.createAttribute('id');
+ id.nodeValue = 'shift_state';
+ style.setAttributeNode(id);
+ var type = document.createAttribute('type');
+ type.nodeValue = 'text/css';
+ style.setAttributeNode(type);
+ document.getElementsByTagName('head')[0].appendChild(style);
+
+ // Set up key bindings
+ this.initializeKeyBindings(box);
+};
+
VT100.prototype.initializeElements = function(container) {
// If the necessary objects have not already been defined in the HTML
// page, create them now.
if (!this.getChildById(this.container, 'reconnect') ||
!this.getChildById(this.container, 'menu') ||
+ !this.getChildById(this.container, 'keyboard') ||
+ !this.getChildById(this.container, 'kbd_button') ||
+ !this.getChildById(this.container, 'kbd_img') ||
!this.getChildById(this.container, 'scrollable') ||
!this.getChildById(this.container, 'console') ||
!this.getChildById(this.container, 'alt_console') ||
'<div id="cursize" style="visibility: hidden">' +
'</div>' +
'<div id="menu"></div>' +
+ '<div id="keyboard" unselectable="on">' +
+ KEYBOARD +
+ '</div>' +
'<div id="scrollable">' +
+ '<table id="kbd_button">' +
+ '<tr><td width="100%"> </td>' +
+ '<td><img id="kbd_img" src="keyboard.png" /></td>' +
+ '<td> </td></tr>' +
+ '</table>' +
'<pre id="lineheight"> </pre>' +
'<pre id="console">' +
'<pre></pre>' +
this.reconnectBtn = this.getChildById(this.container,'reconnect');
this.curSizeBox = this.getChildById(this.container, 'cursize');
this.menu = this.getChildById(this.container, 'menu');
+ this.keyboard = this.getChildById(this.container, 'keyboard');
+ this.keyboardImage = this.getChildById(this.container, 'kbd_img');
this.scrollable = this.getChildById(this.container,
'scrollable');
this.lineheight = this.getChildById(this.container,
// Hide context menu
this.hideContextMenu();
+ // Set up onscreen soft keyboard
+ this.initializeKeyboard();
+
// Add listener to reconnect button
this.addListener(this.reconnectBtn.firstChild, 'click',
function(vt100) {
VT100.prototype.showReconnect = function(state) {
if (state) {
+ this.hideSoftKeyboard();
this.reconnectBtn.style.visibility = '';
} else {
this.reconnectBtn.style.visibility = 'hidden';
};
VT100.prototype.resizer = function() {
+ // Hide onscreen soft keyboard
+ this.hideSoftKeyboard();
+
// The cursor can get corrupted if the print-preview is displayed in Firefox.
// Recreating it, will repair it.
var newCursor = document.createElement('pre');
return false;
};
+VT100.prototype.mousePosition = function(event) {
+ var offsetX = this.container.offsetLeft;
+ var offsetY = this.container.offsetTop;
+ for (var e = this.container; e = e.offsetParent; ) {
+ offsetX += e.offsetLeft;
+ offsetY += e.offsetTop;
+ }
+ return [ event.clientX - offsetX,
+ event.clientY - offsetY ];
+};
+
VT100.prototype.mouseEvent = function(event, type) {
// If any text is currently selected, do not move the focus as that would
// invalidate the selection.
}
// Compute mouse position in characters.
- var offsetX = this.container.offsetLeft;
- var offsetY = this.container.offsetTop;
- for (var e = this.container; e = e.offsetParent; ) {
- offsetX += e.offsetLeft;
- offsetY += e.offsetTop;
- }
- var x = (event.clientX - offsetX) / this.cursorWidth;
- var y = ((event.clientY - offsetY) + this.scrollable.offsetTop) /
- this.cursorHeight - this.numScrollbackLines;
+ var position = this.mousePosition(event);
+ var x = Math.floor(position[0] / this.cursorWidth);
+ var y = Math.floor((position[1] + this.scrollable.scrollTop) /
+ this.cursorHeight) - this.numScrollbackLines;
var inside = true;
if (x >= this.terminalWidth) {
x = this.terminalWidth - 1;
// Bring up context menu.
if (button == 2 && !event.shiftKey) {
if (type == MOUSE_DOWN) {
- this.showContextMenu(event.clientX - offsetX, event.clientY - offsetY);
+ this.showContextMenu(position[0], position[1]);
}
return this.cancelEvent(event);
}
(typeof elem.textContent == 'undefined' ? elem.innerText : '');
};
+VT100.prototype.setTextContentRaw = function(elem, s) {
+ // Updating the content of an element is an expensive operation. It actually
+ // pays off to first check whether the element is still unchanged.
+ if (typeof elem.textContent == 'undefined') {
+ if (elem.innerText != s) {
+ try {
+ elem.innerText = s;
+ } catch (e) {
+ // Very old versions of IE do not allow setting innerText. Instead,
+ // remove all children, by setting innerHTML and then set the text
+ // using DOM methods.
+ elem.innerHTML = '';
+ elem.appendChild(document.createTextNode(
+ this.replaceChar(s, ' ', '\u00A0')));
+ }
+ }
+ } else {
+ if (elem.textContent != s) {
+ elem.textContent = s;
+ }
+ }
+};
+
VT100.prototype.setTextContent = function(elem, s) {
// Check if we find any URLs in the text. If so, automatically convert them
// to links.
return;
}
- // Updating the content of an element is an expensive operation. It actually
- // pays off to first check whether the element is still unchanged.
- if (typeof elem.textContent == 'undefined') {
- if (elem.innerText != s) {
- try {
- elem.innerText = s;
- } catch (e) {
- // Very old versions of IE do not allow setting innerText. Instead,
- // remove all children, by setting innerHTML and then set the text
- // using DOM methods.
- elem.innerHTML = '';
- elem.appendChild(document.createTextNode(
- this.replaceChar(s, ' ', '\u00A0')));
- }
- }
- } else {
- if (elem.textContent != s) {
- elem.textContent = s;
- }
- }
+ this.setTextContentRaw(elem, s);
};
VT100.prototype.insertBlankLine = function(y, color, style) {
this.console[this.currentScreen].style.display = '';
// Select appropriate character pitch.
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter' ];
- for (var i = 0; i < styles.length; ++i) {
- if (typeof this.console[0].style[styles[i]] != 'undefined') {
- if (state) {
- // Upon enabling the alternate screen, we switch to 80 column mode. But
- // upon returning to the regular screen, we restore the mode that was
- // in effect previously.
- this.console[1].style[styles[i]] = '';
- }
- var style =
- this.console[this.currentScreen].style[styles[i]];
- this.cursor.style[styles[i]] = style;
- this.space.style[styles[i]] = style;
- this.scale = style == '' ? 1.0:1.65;
- if (styles[i] == 'filter') {
- this.console[this.currentScreen].style.width = style == '' ? '165%':'';
- }
- break;
+ var transform = this.getTransformName();
+ if (transform) {
+ if (state) {
+ // Upon enabling the alternate screen, we switch to 80 column mode. But
+ // upon returning to the regular screen, we restore the mode that was
+ // in effect previously.
+ this.console[1].style[transform] = '';
+ }
+ var style =
+ this.console[this.currentScreen].style[transform];
+ this.cursor.style[transform] = style;
+ this.space.style[transform] = style;
+ this.scale = style == '' ? 1.0:1.65;
+ if (transform == 'filter') {
+ this.console[this.currentScreen].style.width = style == '' ? '165%':'';
}
}
this.resizer();
this.visualBell = !this.visualBell;
};
+VT100.prototype.toggleSoftKeyboard = function() {
+ this.softKeyboard = !this.softKeyboard;
+ this.keyboardImage.style.visibility = this.softKeyboard ? 'visible' : '';
+};
+
+VT100.prototype.deselectKeys = function(elem) {
+ if (elem && elem.className == 'selected') {
+ elem.className = '';
+ }
+ for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ this.deselectKeys(elem);
+ }
+};
+
+VT100.prototype.showSoftKeyboard = function() {
+ // Make sure no key is currently selected
+ this.lastSelectedKey = undefined;
+ this.deselectKeys(this.keyboard);
+ this.isShift = false;
+ this.showShiftState(false);
+ this.isCtrl = false;
+ this.showCtrlState(false);
+ this.isAlt = false;
+ this.showAltState(false);
+
+ this.keyboard.style.left = '0px';
+ this.keyboard.style.top = '0px';
+ this.keyboard.style.width = this.container.offsetWidth + 'px';
+ this.keyboard.style.height = this.container.offsetHeight + 'px';
+ this.keyboard.style.visibility = 'hidden';
+ this.keyboard.style.display = '';
+
+ var kbd = this.keyboard.firstChild;
+ var scale = 1.0;
+ var transform = this.getTransformName();
+ if (transform) {
+ kbd.style[transform] = '';
+ if (kbd.offsetWidth > 0.9 * this.container.offsetWidth) {
+ scale = (kbd.offsetWidth/
+ this.container.offsetWidth)/0.9;
+ }
+ if (kbd.offsetHeight > 0.9 * this.container.offsetHeight) {
+ scale = Math.max((kbd.offsetHeight/
+ this.container.offsetHeight)/0.9);
+ }
+ var style = this.getTransformStyle(transform,
+ scale > 1.0 ? scale : undefined);
+ kbd.style[transform] = style;
+ }
+ if (transform == 'filter') {
+ scale = 1.0;
+ }
+ kbd.style.left = ((this.container.offsetWidth -
+ kbd.offsetWidth/scale)/2) + 'px';
+ kbd.style.top = ((this.container.offsetHeight -
+ kbd.offsetHeight/scale)/2) + 'px';
+
+ this.keyboard.style.visibility = 'visible';
+};
+
+VT100.prototype.hideSoftKeyboard = function() {
+ this.keyboard.style.display = 'none';
+};
+
VT100.prototype.toggleCursorBlinking = function() {
this.blinkingCursor = !this.blinkingCursor;
};
'<li>' +
(this.visualBell ? '<img src="enabled.gif" />' : '') +
'Visual Bell</li>'+
+ '<li>' +
+ (this.softKeyboard ? '<img src="enabled.gif" />' : '') +
+ 'Onscreen Keyboard</li>' +
'<li id="endconfig">' +
(this.blinkingCursor ? '<img src="enabled.gif" />' : '') +
'Blinking Cursor</li>'+
// Actions for default items
var actions = [ this.copyLast, p, this.reset,
this.toggleUTF, this.toggleBell,
+ this.toggleSoftKeyboard,
this.toggleCursorBlinking ];
// Actions for user CSS styles (if any)
}
// Position menu next to the mouse pointer
- if (x + popup.clientWidth > this.container.offsetWidth) {
- x = this.container.offsetWidth - popup.clientWidth;
+ this.menu.style.left = '0px';
+ this.menu.style.top = '0px';
+ this.menu.style.width = this.container.offsetWidth + 'px';
+ this.menu.style.height = this.container.offsetHeight + 'px';
+ popup.style.left = '0px';
+ popup.style.top = '0px';
+
+ var margin = 2;
+ if (x + popup.clientWidth >= this.container.offsetWidth - margin) {
+ x = this.container.offsetWidth-popup.clientWidth - margin - 1;
}
- if (x < 0) {
- x = 0;
+ if (x < margin) {
+ x = margin;
}
- if (y + popup.clientHeight > this.container.offsetHeight) {
- y = this.container.offsetHeight-popup.clientHeight;
+ if (y + popup.clientHeight >= this.container.offsetHeight - margin) {
+ y = this.container.offsetHeight-popup.clientHeight - margin - 1;
}
- if (y < 0) {
- y = 0;
+ if (y < margin) {
+ y = margin;
}
popup.style.left = x + 'px';
popup.style.top = y + 'px';
// Block all other interactions with the terminal emulator
- this.menu.style.left = '0px';
- this.menu.style.top = '0px';
- this.menu.style.width = this.container.offsetWidth + 'px';
- this.menu.style.height = this.container.offsetHeight + 'px';
this.addListener(this.menu, 'click', function(vt100) {
return function() {
vt100.hideContextMenu();
this.savedY[this.currentScreen]);
};
-VT100.prototype.set80_132Mode = function(state) {
- var transform = undefined;
- var styles = [ 'transform',
- 'WebkitTransform',
- 'MozTransform',
- 'filter'
- ];
+VT100.prototype.getTransformName = function() {
+ var styles = [ 'transform', 'WebkitTransform', 'MozTransform', 'filter' ];
for (var i = 0; i < styles.length; ++i) {
if (typeof this.console[0].style[styles[i]] != 'undefined') {
- transform = styles[i];
- break;
+ return styles[i];
}
}
+ return undefined;
+};
+VT100.prototype.getTransformStyle = function(transform, scale) {
+ return scale && scale != 1.0
+ ? transform == 'filter'
+ ? 'progid:DXImageTransform.Microsoft.Matrix(' +
+ 'M11=' + (1.0/scale) + ',M12=0,M21=0,M22=1,' +
+ "sizingMethod='auto expand')"
+ : 'translateX(-50%) ' +
+ 'scaleX(' + (1.0/scale) + ') ' +
+ 'translateX(50%)'
+ : '';
+};
+
+VT100.prototype.set80_132Mode = function(state) {
+ var transform = this.getTransformName();
if (transform) {
if ((this.console[this.currentScreen].style[transform] != '') == state) {
return;
}
- var style =
- state ? transform == 'filter'
- ? 'progid:DXImageTransform.Microsoft.Matrix(' +
- 'M11=0.606060606060606060606,M12=0,M21=0,M22=1,' +
- "sizingMethod='auto expand')"
- : 'translateX(-50%) ' +
- 'scaleX(0.606060606060606060606) ' +
- 'translateX(50%)'
- : '';
+ var style = state ?
+ this.getTransformStyle(transform, 1.65):'';
this.console[this.currentScreen].style[transform] = style;
- this.cursor.style[transform] = style;
- this.space.style[transform] = style;
- this.scale = state ? 1.65 : 1.0;
+ this.cursor.style[transform] = style;
+ this.space.style[transform] = style;
+ this.scale = state ? 1.65 : 1.0;
if (transform == 'filter') {
- this.console[this.currentScreen].style.width = state ? '165%' : '';
+ this.console[this.currentScreen].style.width = state ? '165%' : '';
}
this.resizer();
}