reworked autorestore + added touchkeyboard compatibility
This commit is contained in:
parent
ce44449fc4
commit
4f83e1af0b
|
@ -36,7 +36,7 @@ AFRAME.registerComponent('codemirror', {
|
||||||
|
|
||||||
css: (me) => `.CodeMirror{
|
css: (me) => `.CodeMirror{
|
||||||
width: ${me.com.data.width}px !important;
|
width: ${me.com.data.width}px !important;
|
||||||
height: ${me.com.data.height}px !important;
|
height: ${me.com.data.height-30}px !important;
|
||||||
}
|
}
|
||||||
.codemirror *{
|
.codemirror *{
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -45,7 +45,10 @@ AFRAME.registerComponent('codemirror', {
|
||||||
letter-spacing: 0 !important;
|
letter-spacing: 0 !important;
|
||||||
text-shadow: 0px 0px 10px #F075;
|
text-shadow: 0px 0px 10px #F075;
|
||||||
}
|
}
|
||||||
#${me.dom.id} .wb-body { overflow:hidden; }
|
|
||||||
|
.wb-body:has(> .codemirror){
|
||||||
|
overflow:hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.CodeMirror {
|
.CodeMirror {
|
||||||
margin-top:18px;
|
margin-top:18px;
|
||||||
|
@ -78,11 +81,30 @@ AFRAME.registerComponent('codemirror', {
|
||||||
this.editor.updateFile( this.data.file, instance.getValue() )
|
this.editor.updateFile( this.data.file, instance.getValue() )
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this
|
||||||
|
.handleFocus()
|
||||||
|
|
||||||
setTimeout( () => {
|
setTimeout( () => {
|
||||||
this.el.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}`) // only show aframe-html in xr
|
this.el.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}`) // only show aframe-html in xr
|
||||||
},1500)
|
},1500)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleFocus: function(){
|
||||||
|
const focus = (showdom) => (e) => {
|
||||||
|
if( this.editor ){
|
||||||
|
this.editor.focus()
|
||||||
|
}
|
||||||
|
if( this.el.components.window && this.data.renderer == 'canvas'){
|
||||||
|
this.el.components.window.show( showdom )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.el.addEventListener('obbcollisionstarted', focus(false) )
|
||||||
|
this.el.sceneEl.addEventListener('enter-vr', focus(false) )
|
||||||
|
this.el.sceneEl.addEventListener('enter-ar', focus(false) )
|
||||||
|
this.el.sceneEl.addEventListener('exit-vr', focus(true) )
|
||||||
|
this.el.sceneEl.addEventListener('exit-ar', focus(true) )
|
||||||
|
},
|
||||||
|
|
||||||
updateFile: async function(file,str){
|
updateFile: async function(file,str){
|
||||||
// we don't do via shellcmd: isoterminal.exec(`echo '${str}' > ${file}`,1)
|
// we don't do via shellcmd: isoterminal.exec(`echo '${str}' > ${file}`,1)
|
||||||
// as it would require all kindof ugly stringescaping
|
// as it would require all kindof ugly stringescaping
|
||||||
|
|
|
@ -21,7 +21,7 @@ if( !AFRAME.components['html-as-texture-in-xr'] ){
|
||||||
this.el.setAttribute("html",`html: ${this.data.domid}; cursor:#cursor; xrlayer: true`)
|
this.el.setAttribute("html",`html: ${this.data.domid}; cursor:#cursor; xrlayer: true`)
|
||||||
this.el.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' )
|
this.el.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' )
|
||||||
if( this.data.faceuser ){
|
if( this.data.faceuser ){
|
||||||
this.el.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) )
|
this.el.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.8) )
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ if( typeof AFRAME != 'undefined '){
|
||||||
overlayfs: { type:"string"},
|
overlayfs: { type:"string"},
|
||||||
width: { type: 'number',"default": -1 },
|
width: { type: 'number',"default": -1 },
|
||||||
height: { type: 'number',"default": -1 },
|
height: { type: 'number',"default": -1 },
|
||||||
|
depth: { type: 'number',"default": 0.03 },
|
||||||
lineHeight: { type: 'number',"default": 18 },
|
lineHeight: { type: 'number',"default": 18 },
|
||||||
padding: { type: 'number',"default": 18 },
|
padding: { type: 'number',"default": 18 },
|
||||||
minimized: { type: 'boolean',"default":false},
|
minimized: { type: 'boolean',"default":false},
|
||||||
|
@ -44,19 +45,18 @@ if( typeof AFRAME != 'undefined '){
|
||||||
muteUntilPrompt:{ type: 'boolean',"default":true}, // mute stdout until a prompt is detected in ISO
|
muteUntilPrompt:{ type: 'boolean',"default":true}, // mute stdout until a prompt is detected in ISO
|
||||||
HUD: { type: 'boolean',"default":false}, // link to camera movement
|
HUD: { type: 'boolean',"default":false}, // link to camera movement
|
||||||
transparent: { type:'boolean', "default":false }, // need good gpu
|
transparent: { type:'boolean', "default":false }, // need good gpu
|
||||||
memory: { type: 'number', "default":64 }, // VM memory (in MB)
|
memory: { type: 'number', "default":40 }, // VM memory (in MB) [NOTE: quest or smartphone might crash > 40mb ]
|
||||||
bufferLatency: { type: 'number', "default":30 }, // in ms: bufferlatency from webworker to xterm (batch-update every char to texture)
|
bufferLatency: { type: 'number', "default":1 }, // in ms: bufferlatency from webworker to xterm (batch-update every char to texture)
|
||||||
debug: { type: 'boolean', "default":false }
|
debug: { type: 'boolean', "default":false }
|
||||||
},
|
},
|
||||||
|
|
||||||
init: function(){
|
init: function(){
|
||||||
this.el.object3D.visible = false
|
this.el.object3D.visible = false
|
||||||
if( this.data.width == -1 ) this.data.width = document.body.offsetWidth
|
|
||||||
if( this.data.height == -1 ) this.data.height = document.body.offsetHeight
|
|
||||||
this.data.width -= this.data.padding*2
|
|
||||||
this.data.height -= this.data.padding*2
|
|
||||||
|
|
||||||
|
this.calculateDimension()
|
||||||
this.initHud()
|
this.initHud()
|
||||||
|
this.setupBox()
|
||||||
|
|
||||||
fetch(this.data.iso,{method: 'HEAD'})
|
fetch(this.data.iso,{method: 'HEAD'})
|
||||||
.then( (res) => {
|
.then( (res) => {
|
||||||
if( res.status != 200 ) throw 'not found'
|
if( res.status != 200 ) throw 'not found'
|
||||||
|
@ -79,17 +79,17 @@ if( typeof AFRAME != 'undefined '){
|
||||||
selfcontain: "com/selfcontainer.js",
|
selfcontain: "com/selfcontainer.js",
|
||||||
// html to texture
|
// html to texture
|
||||||
htmlinxr: "com/html-as-texture-in-xr.js",
|
htmlinxr: "com/html-as-texture-in-xr.js",
|
||||||
// isoterminal features
|
// isoterminal global features
|
||||||
PromiseWorker: "com/isoterminal/PromiseWorker.js",
|
PromiseWorker: "com/isoterminal/PromiseWorker.js",
|
||||||
ISOTerminal: "com/isoterminal/ISOTerminal.js",
|
ISOTerminal: "com/isoterminal/ISOTerminal.js",
|
||||||
localforage: "https://cdn.rawgit.com/mozilla/localForage/master/dist/localforage.js"
|
localforage: "com/isoterminal/localforage.js",
|
||||||
},
|
},
|
||||||
|
|
||||||
dom: {
|
dom: {
|
||||||
scale: 1.0,
|
scale: 0.66,
|
||||||
events: ['click','keydown'],
|
events: ['click','keydown'],
|
||||||
html: (me) => `<div class="isoterminal">
|
html: (me) => `<div class="isoterminal">
|
||||||
<div id="vt100" tabindex="0">
|
<div id="term" tabindex="0">
|
||||||
<pre></pre>
|
<pre></pre>
|
||||||
</div>
|
</div>
|
||||||
</div>`,
|
</div>`,
|
||||||
|
@ -105,7 +105,7 @@ if( typeof AFRAME != 'undefined '){
|
||||||
position:relative;
|
position:relative;
|
||||||
line-height: ${me.com.data.lineHeight}px;
|
line-height: ${me.com.data.lineHeight}px;
|
||||||
}
|
}
|
||||||
#vt100 {
|
#term {
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
|
@ -127,10 +127,6 @@ if( typeof AFRAME != 'undefined '){
|
||||||
border:none;
|
border:none;
|
||||||
padding:none;
|
padding:none;
|
||||||
}
|
}
|
||||||
span blink:last-of-type{
|
|
||||||
border-right: 8px solid #F07;
|
|
||||||
padding-right: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#overlay .winbox:has(> .isoterminal){
|
#overlay .winbox:has(> .isoterminal){
|
||||||
background:transparent;
|
background:transparent;
|
||||||
|
@ -218,8 +214,10 @@ if( typeof AFRAME != 'undefined '){
|
||||||
this.term = new ISOTerminal(instance,this.data)
|
this.term = new ISOTerminal(instance,this.data)
|
||||||
|
|
||||||
instance.addEventListener('DOMready', () => {
|
instance.addEventListener('DOMready', () => {
|
||||||
instance.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}; faceuser: true`)
|
this.setupVT100(instance)
|
||||||
setTimeout( () => this.setupVT100(instance),100)
|
setTimeout( () => {
|
||||||
|
instance.setAttribute("html-as-texture-in-xr", `domid: #term; faceuser: true`)
|
||||||
|
},100)
|
||||||
//instance.winbox.resize(720,380)
|
//instance.winbox.resize(720,380)
|
||||||
let size = `width: ${this.data.width}; height: ${this.data.height}`
|
let size = `width: ${this.data.width}; height: ${this.data.height}`
|
||||||
instance.setAttribute("window", `title: xrsh.iso; uid: ${instance.uid}; attach: #overlay; dom: #${instance.dom.id}; ${size}; min: ${this.data.minimized}; max: ${this.data.maximized}`)
|
instance.setAttribute("window", `title: xrsh.iso; uid: ${instance.uid}; attach: #overlay; dom: #${instance.dom.id}; ${size}; min: ${this.data.minimized}; max: ${this.data.maximized}`)
|
||||||
|
@ -231,6 +229,8 @@ if( typeof AFRAME != 'undefined '){
|
||||||
// run iso
|
// run iso
|
||||||
let opts = {dom:instance.dom}
|
let opts = {dom:instance.dom}
|
||||||
for( let i in this.data ) opts[i] = this.data[i]
|
for( let i in this.data ) opts[i] = this.data[i]
|
||||||
|
opts.cols = this.cols
|
||||||
|
opts.rows = this.rows
|
||||||
this.term.start(opts)
|
this.term.start(opts)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -262,6 +262,7 @@ if( typeof AFRAME != 'undefined '){
|
||||||
if( this.el.components.window && this.data.renderer == 'canvas'){
|
if( this.el.components.window && this.data.renderer == 'canvas'){
|
||||||
this.el.components.window.show( showdom )
|
this.el.components.window.show( showdom )
|
||||||
}
|
}
|
||||||
|
this.el.emit('focus',e.detail)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.el.addEventListener('obbcollisionstarted', focus(false) )
|
this.el.addEventListener('obbcollisionstarted', focus(false) )
|
||||||
|
@ -290,17 +291,20 @@ if( typeof AFRAME != 'undefined '){
|
||||||
},
|
},
|
||||||
|
|
||||||
setupVT100: function(instance){
|
setupVT100: function(instance){
|
||||||
const el = this.el.dom.querySelector('#vt100')
|
const el = this.el.dom.querySelector('#term')
|
||||||
this.vt100 = new VT100(
|
const opts = {
|
||||||
Math.floor(this.data.width/this.data.lineHeight),
|
cols: this.cols,
|
||||||
Math.floor(this.data.height*0.8/this.data.lineHeight),
|
rows: this.rows,
|
||||||
el,
|
el_or_id: el,
|
||||||
100
|
max_scroll_lines: 100,
|
||||||
)
|
nodim: true
|
||||||
|
}
|
||||||
|
this.vt100 = new VT100( opts )
|
||||||
|
this.vt100.el = el
|
||||||
this.vt100.curs_set( 1, true)
|
this.vt100.curs_set( 1, true)
|
||||||
el.focus()
|
el.focus()
|
||||||
|
this.el.addEventListener('focus', () => el.focus())
|
||||||
this.vt100.getch( (ch,t) => {
|
this.vt100.getch( (ch,t) => {
|
||||||
console.log(ch)
|
|
||||||
this.term.send( ch )
|
this.term.send( ch )
|
||||||
this.vt100.curs_set( 0, true)
|
this.vt100.curs_set( 0, true)
|
||||||
})
|
})
|
||||||
|
@ -323,6 +327,27 @@ if( typeof AFRAME != 'undefined '){
|
||||||
//})
|
//})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setupBox: function(){
|
||||||
|
// setup slightly bigger black backdrop (this.el.getObject3D("mesh"))
|
||||||
|
const w = this.data.width/950;
|
||||||
|
const h = this.data.height/950;
|
||||||
|
this.el.box = document.createElement('a-entity')
|
||||||
|
this.el.box.setAttribute("geometry",`primitive: box; width:${w}; height:${h}; depth: -${this.data.depth}`)
|
||||||
|
this.el.box.setAttribute("material","shader:flat; color:black; opacity:0.9; transparent:true; ")
|
||||||
|
this.el.box.setAttribute("position",`0 0 ${(this.data.depth/2)-0.001}`)
|
||||||
|
this.el.appendChild(this.el.box)
|
||||||
|
},
|
||||||
|
|
||||||
|
calculateDimension: function(){
|
||||||
|
if( this.data.width == -1 ) this.data.width = document.body.offsetWidth
|
||||||
|
if( this.data.height == -1 ) this.data.height = document.body.offsetHeight
|
||||||
|
if( this.data.height > this.data.width ) this.data.height = this.data.width // mobile smartphone fix
|
||||||
|
this.data.width -= this.data.padding*2
|
||||||
|
this.data.height -= this.data.padding*2
|
||||||
|
this.cols = Math.floor(this.data.width/this.data.lineHeight*1.9)
|
||||||
|
this.rows = Math.floor(this.data.height*0.5/this.data.lineHeight*1.7) // keep extra height for mobile browser bottom-bar (android)
|
||||||
|
},
|
||||||
|
|
||||||
events:{
|
events:{
|
||||||
|
|
||||||
// combined AFRAME+DOM reactive events
|
// combined AFRAME+DOM reactive events
|
||||||
|
|
|
@ -61,11 +61,11 @@ ISOTerminal.prototype.convert = {
|
||||||
const bytes = new Uint8Array(buffer);
|
const bytes = new Uint8Array(buffer);
|
||||||
const len = bytes.byteLength;
|
const len = bytes.byteLength;
|
||||||
for (let i = 0; i < len; i++) binary += String.fromCharCode(bytes[i]);
|
for (let i = 0; i < len; i++) binary += String.fromCharCode(bytes[i]);
|
||||||
return window.btoa(binary);
|
return btoa(binary);
|
||||||
},
|
},
|
||||||
|
|
||||||
base64ToArrayBuffer: function(base64) {
|
base64ToArrayBuffer: function(base64) {
|
||||||
const binaryString = window.atob(base64);
|
const binaryString = atob(base64);
|
||||||
const len = binaryString.length;
|
const len = binaryString.length;
|
||||||
const bytes = new Uint8Array(len);
|
const bytes = new Uint8Array(len);
|
||||||
|
|
||||||
|
@ -211,11 +211,14 @@ ISOTerminal.prototype.startVM = function(opts){
|
||||||
\r[38;5;165m ▬▬▬▬▬▬▬▬ https://xrsh.isvery.ninja ▬▬▬▬▬▬▬▬▬▬▬▬
|
\r[38;5;165m ▬▬▬▬▬▬▬▬ https://xrsh.isvery.ninja ▬▬▬▬▬▬▬▬▬▬▬▬
|
||||||
\r[38;5;165m local-first, polyglot, unixy WebXR IDE & runtime
|
\r[38;5;165m local-first, polyglot, unixy WebXR IDE & runtime
|
||||||
\r
|
\r
|
||||||
\r credits: NLnet | @nlnet@nlnet.nl
|
\r credits
|
||||||
\r Leon van Kammen | @lvk@mastodon.online
|
\r -------
|
||||||
\r Fabien Benetou | @utopiah@mastodon.pirateparty.be
|
\r @nlnet@nlnet.nl
|
||||||
\r Mr Doob | THREE.js
|
\r @lvk@mastodon.online
|
||||||
\r Diego Marcos | AFRAME.js
|
\r @utopiah@mastodon.pirateparty.be
|
||||||
|
\r https://www.w3.org/TR/webxr
|
||||||
|
\r https://three.org
|
||||||
|
\r https://aframe.org
|
||||||
`
|
`
|
||||||
|
|
||||||
const text_color = "\r[38;5;129m"
|
const text_color = "\r[38;5;129m"
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
// https://raw.githubusercontent.com/vsinitsyn/vt100/refs/heads/coffeescript/public/javascripts/VT100.js
|
// https://raw.githubusercontent.com/vetupinitsyn/vt100/refs/heads/coffeescript/public/javascripts/VT100.js
|
||||||
//
|
//
|
||||||
// VT100.js -- a text terminal emulator in JavaScript with a ncurses-like
|
// VT100.js -- a text terminal emulator in JavaScript with a ncurses-like
|
||||||
// interface and a POSIX-like interface. (The POSIX-like calls are
|
// interface and a POSIX-like interface. (The POSIX-like calls are
|
||||||
// implemented on top of the ncurses-like calls, not the other way round.)
|
// implemented on top of the ncurses-like calls, not the other way round.)
|
||||||
|
//
|
||||||
|
// required markup:
|
||||||
|
//
|
||||||
|
// <div id="term" tabindex="0">
|
||||||
|
// <pre></pre>
|
||||||
|
// </div>
|
||||||
|
|
||||||
//
|
//
|
||||||
// Released under the GNU LGPL v2.1, by Frank Bi <bi@zompower.tk>
|
// Released under the GNU LGPL v2.1, by Frank Bi <bi@zompower.tk>
|
||||||
//
|
//
|
||||||
|
@ -77,8 +84,10 @@
|
||||||
// interpreted and acted on.
|
// interpreted and acted on.
|
||||||
|
|
||||||
// constructor
|
// constructor
|
||||||
function VT100(wd, ht, el_or_id, max_scroll_lines, fg, bg)
|
function VT100(opts)
|
||||||
{
|
{
|
||||||
|
this.opts = opts
|
||||||
|
let {cols, rows, el_or_id, max_scroll_lines, fg, bg, nodim} = opts
|
||||||
if (!max_scroll_lines) {
|
if (!max_scroll_lines) {
|
||||||
max_scroll_lines = 1000;
|
max_scroll_lines = 1000;
|
||||||
}
|
}
|
||||||
|
@ -92,20 +101,20 @@ function VT100(wd, ht, el_or_id, max_scroll_lines, fg, bg)
|
||||||
var r;
|
var r;
|
||||||
var c;
|
var c;
|
||||||
var scr = typeof el_or_id == 'string' ? document.getElementById(el_or_id) : el_or_id
|
var scr = typeof el_or_id == 'string' ? document.getElementById(el_or_id) : el_or_id
|
||||||
this.wd_ = wd;
|
this.wd_ = cols;
|
||||||
this.ht_ = ht;
|
this.ht_ = rows;
|
||||||
// Keep up to max_scroll_lines of scrollback history.
|
// Keep up to max_scroll_lines of scrollback history.
|
||||||
this.max_ht_ = max_scroll_lines;
|
this.max_ht_ = max_scroll_lines;
|
||||||
this._set_colors(fg, bg);
|
this._set_colors(fg, bg);
|
||||||
this.text_ = new Array(ht);
|
this.text_ = new Array(rows);
|
||||||
this.attr_ = new Array(ht);
|
this.attr_ = new Array(rows);
|
||||||
this.redraw_ = new Array(ht);
|
this.redraw_ = new Array(rows);
|
||||||
this.scroll_region_ = [0, ht-1];
|
this.scroll_region_ = [0, rows-1];
|
||||||
this.start_row_id = 0;
|
this.start_row_id = 0;
|
||||||
this.num_rows_ = ht;
|
this.num_rows_ = rows;
|
||||||
for (r = 0; r < ht; ++r) {
|
for (r = 0; r < rows; ++r) {
|
||||||
this.text_[r] = new Array(wd);
|
this.text_[r] = new Array(cols);
|
||||||
this.attr_[r] = new Array(wd);
|
this.attr_[r] = new Array(cols);
|
||||||
this.redraw_[r] = 1;
|
this.redraw_[r] = 1;
|
||||||
}
|
}
|
||||||
this.scr_ = scr;
|
this.scr_ = scr;
|
||||||
|
@ -116,10 +125,14 @@ function VT100(wd, ht, el_or_id, max_scroll_lines, fg, bg)
|
||||||
this.key_buf_ = [];
|
this.key_buf_ = [];
|
||||||
this.echo_ = false;
|
this.echo_ = false;
|
||||||
this.esc_state_ = 0;
|
this.esc_state_ = 0;
|
||||||
this.log_level_ = VT100.DEBUG //WARN;
|
this.log_level_ = VT100.WARN
|
||||||
|
|
||||||
this.clear_all();
|
this.clear_all();
|
||||||
this.refresh();
|
|
||||||
|
// rate limit this.refresh
|
||||||
|
this.refresh = this.throttleSmart( VT100.prototype.refresh.bind(this), 100)
|
||||||
|
|
||||||
|
this.setupTouchInputFallback() // smartphone
|
||||||
}
|
}
|
||||||
|
|
||||||
// public constants -- colours and colour pairs
|
// public constants -- colours and colour pairs
|
||||||
|
@ -172,6 +185,7 @@ VT100.handle_onkeypress_ = function VT100_handle_onkeypress(event,cb)
|
||||||
var vt = VT100.the_vt_, ch;
|
var vt = VT100.the_vt_, ch;
|
||||||
if (vt === undefined)
|
if (vt === undefined)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
//if ( event.keyCode != undefined || !event.charCode){
|
//if ( event.keyCode != undefined || !event.charCode){
|
||||||
// ch = event.keyCode;
|
// ch = event.keyCode;
|
||||||
// if (ch == 13)
|
// if (ch == 13)
|
||||||
|
@ -180,11 +194,11 @@ VT100.handle_onkeypress_ = function VT100_handle_onkeypress(event,cb)
|
||||||
// return true;
|
// return true;
|
||||||
// ch = String.fromCharCode(ch);
|
// ch = String.fromCharCode(ch);
|
||||||
//} else {
|
//} else {
|
||||||
ch = event.charCode;
|
|
||||||
//dump("ch: " + ch + "\n");
|
//dump("ch: " + ch + "\n");
|
||||||
//dump("ctrl?: " + event.ctrlKey + "\n");
|
//dump("ctrl?: " + event.ctrlKey + "\n");
|
||||||
vt.debug("onkeypress:: keyCode: " + event.keyCode + ", ch: " + event.charCode);
|
vt.debug("onkeypress:: ch: " + event.code + " ,key: "+event.key);
|
||||||
if (ch) {
|
if (event.key.length == 1) {
|
||||||
|
ch = event.key.charCodeAt(0)
|
||||||
if (ch > 255)
|
if (ch > 255)
|
||||||
return true;
|
return true;
|
||||||
if (event.ctrlKey && event.shiftKey) {
|
if (event.ctrlKey && event.shiftKey) {
|
||||||
|
@ -203,51 +217,52 @@ VT100.handle_onkeypress_ = function VT100_handle_onkeypress(event,cb)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case "Backspace":
|
case "Backspace":
|
||||||
ch = '\b';
|
ch = '\b';
|
||||||
break;
|
break;
|
||||||
case "Tab":
|
case "Tab":
|
||||||
ch = '\t';
|
ch = '\t';
|
||||||
break;
|
break;
|
||||||
case event.DOM_VK_RETURN:
|
case "Enter":
|
||||||
case event.DOM_VK_ENTER:
|
ch = '\n';
|
||||||
ch = '\r';
|
break;
|
||||||
break;
|
case "ArrowUp":
|
||||||
case event.DOM_VK_UP:
|
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
|
||||||
ch = '\x1b[A';
|
ch = '\x1b[A';
|
||||||
else
|
else
|
||||||
ch = '\x1bOA';
|
ch = '\x1bOA';
|
||||||
break;
|
break;
|
||||||
case event.DOM_VK_DOWN:
|
case "ArrowDown":
|
||||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||||
ch = '\x1b[B';
|
ch = '\x1b[B';
|
||||||
else
|
else
|
||||||
ch = '\x1bOB';
|
ch = '\x1bOB';
|
||||||
break;
|
break;
|
||||||
case event.DOM_VK_RIGHT:
|
case "ArrowRight":
|
||||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||||
ch = '\x1b[C';
|
ch = '\x1b[C';
|
||||||
else
|
else
|
||||||
ch = '\x1bOC';
|
ch = '\x1bOC';
|
||||||
break;
|
break;
|
||||||
case event.DOM_VK_LEFT:
|
case "ArrowLeft":
|
||||||
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
if (this.cursor_key_mode_ == VT100.CK_CURSOR)
|
||||||
ch = '\x1b[D';
|
ch = '\x1b[D';
|
||||||
else
|
else
|
||||||
ch = '\x1bOD';
|
ch = '\x1bOD';
|
||||||
break;
|
break;
|
||||||
case event.DOM_VK_DELETE:
|
case "Delete":
|
||||||
ch = '\x1b[3~';
|
ch = '\x1b[3~';
|
||||||
break;
|
break;
|
||||||
case event.DOM_VK_HOME:
|
case "Home":
|
||||||
ch = '\x1b[H';
|
ch = '\x1b[H';
|
||||||
break;
|
break;
|
||||||
case event.DOM_VK_ESCAPE:
|
case "Escape":
|
||||||
ch = '\x1b';
|
ch = '\x1b';
|
||||||
break;
|
case "Control":
|
||||||
default:
|
break;
|
||||||
return true;
|
default:
|
||||||
|
return true
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Stop the event from doing anything else.
|
// Stop the event from doing anything else.
|
||||||
|
@ -311,39 +326,39 @@ VT100.prototype.html_colours_ = function VT100_html_colours_(attr)
|
||||||
var fg, bg, co0, co1;
|
var fg, bg, co0, co1;
|
||||||
fg = attr.fg;
|
fg = attr.fg;
|
||||||
bg = attr.bg;
|
bg = attr.bg;
|
||||||
switch (attr.mode & (VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD)) {
|
switch (attr.mode & (VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD)) {
|
||||||
case 0:
|
case 0:
|
||||||
case VT100.A_DIM | VT100.A_BOLD:
|
case VT100.A_DIM | VT100.A_BOLD:
|
||||||
co0 = '00';
|
co0 = '00';
|
||||||
if (bg == VT100.COLOR_WHITE)
|
if (bg == VT100.COLOR_WHITE)
|
||||||
co1 = 'ff';
|
co1 = 'ff';
|
||||||
else
|
else
|
||||||
co1 = 'c0';
|
co1 = 'c0';
|
||||||
break;
|
break;
|
||||||
case VT100.A_BOLD:
|
case VT100.A_BOLD:
|
||||||
co0 = '00'; co1 = 'ff';
|
co0 = '00'; co1 = 'ff';
|
||||||
break;
|
break;
|
||||||
case VT100.A_DIM:
|
case VT100.A_DIM:
|
||||||
if (fg == VT100.COLOR_BLACK)
|
if (fg == VT100.COLOR_BLACK)
|
||||||
co0 = '40';
|
co0 = '40';
|
||||||
else
|
else
|
||||||
co0 = '00';
|
co0 = '00';
|
||||||
co1 = '40';
|
co1 = '40';
|
||||||
break;
|
break;
|
||||||
case VT100.A_REVERSE:
|
case VT100.A_REVERSE:
|
||||||
case VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD:
|
case VT100.A_REVERSE | VT100.A_DIM | VT100.A_BOLD:
|
||||||
co0 = 'c0'; co1 = '40';
|
co0 = 'c0'; co1 = 'ff';
|
||||||
break;
|
break;
|
||||||
case VT100.A_REVERSE | VT100.A_BOLD:
|
case VT100.A_REVERSE | VT100.A_BOLD:
|
||||||
co0 = 'c0'; co1 = '00';
|
co0 = 'c0'; co1 = '00';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (fg == VT100.COLOR_BLACK)
|
if (fg == VT100.COLOR_BLACK)
|
||||||
co0 = '80';
|
co0 = '80';
|
||||||
else
|
else
|
||||||
co0 = 'c0';
|
co0 = 'c0';
|
||||||
co1 = 'c0';
|
co1 = 'c0';
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
f: '#' + (fg & 4 ? co1 : co0) +
|
f: '#' + (fg & 4 ? co1 : co0) +
|
||||||
(fg & 2 ? co1 : co0) +
|
(fg & 2 ? co1 : co0) +
|
||||||
|
@ -1283,6 +1298,52 @@ VT100.prototype.warn = function VT100_warn(message) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VT100.prototype.throttleSmart = function throttleSmart(fn, wait) {
|
||||||
|
let timeout, lastArgs;
|
||||||
|
return (...args) => {
|
||||||
|
lastArgs = lastArgs || []
|
||||||
|
if (!timeout) {
|
||||||
|
fn(...args); timeout = setTimeout(() => { fn(...lastArgs); timeout = null; }, wait);
|
||||||
|
} else lastArgs = args;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
VT100.prototype.setupTouchInputFallback = function(){
|
||||||
|
this.scr_.addEventListener('touchend', () => {
|
||||||
|
if( !this.input ){
|
||||||
|
this.form = document.createElement("form")
|
||||||
|
this.form.addEventListener("submit", (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
this.key_buf_.push('\n')
|
||||||
|
setTimeout(VT100.go_getch_, 0);
|
||||||
|
})
|
||||||
|
this.input = document.createElement("input")
|
||||||
|
this.input.setAttribute("cols", this.opts.cols )
|
||||||
|
this.input.setAttribute("rows", this.opts.rows )
|
||||||
|
this.input.style.opacity = '0'
|
||||||
|
this.input.style.position = 'absolute'
|
||||||
|
this.input.style.left = '-9999px'
|
||||||
|
this.form.appendChild(this.input)
|
||||||
|
this.scr_.parentElement.appendChild(this.form)
|
||||||
|
|
||||||
|
this.input.handler = () => {
|
||||||
|
let ch = this.input.value
|
||||||
|
// detect backspace
|
||||||
|
//if( e.inputType == 'deleteContentBackward' ) ch = '\b'
|
||||||
|
this.input.value = ''
|
||||||
|
if( !ch ) return
|
||||||
|
this.key_buf_.push(ch);
|
||||||
|
setTimeout(VT100.go_getch_, 0);
|
||||||
|
this.input.valueLast = this.input.value
|
||||||
|
}
|
||||||
|
this.input.addEventListener('input', this.input.handler )
|
||||||
|
|
||||||
|
}
|
||||||
|
setTimeout( () => this.input.focus(), 10 )
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function dump(x) {
|
function dump(x) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
console.log(x)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,31 @@
|
||||||
if( typeof emulator != 'undefined' ){
|
if( typeof emulator != 'undefined' ){
|
||||||
// inside worker-thread
|
// inside worker-thread
|
||||||
|
importScripts("localforage.js") // we don't instance it again here (just use its functions)
|
||||||
|
|
||||||
this['emulator.restore_state'] = async function(data){
|
this['emulator.restore_state'] = async function(data){
|
||||||
await emulator.restore_state(data)
|
return new Promise( (resolve,reject) => {
|
||||||
console.log("restored state")
|
localforage.getItem("state", async (err,stateBase64) => {
|
||||||
this.postMessage({event:"state_restored",data:false})
|
if( stateBase64 && !err ){
|
||||||
|
state = ISOTerminal.prototype.convert.base64ToArrayBuffer( stateBase64 )
|
||||||
|
await emulator.restore_state(state)
|
||||||
|
console.log("restored state")
|
||||||
|
}else return reject("worker.js: emulator.restore_state (could not get state from localforage)")
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
this['emulator.save_state'] = async function(){
|
this['emulator.save_state'] = async function(){
|
||||||
console.log("saving session")
|
console.log("saving session")
|
||||||
let state = await emulator.save_state()
|
let state = await emulator.save_state()
|
||||||
this.postMessage({event:"state_saved",data:state},[state])
|
localforage.setDriver([
|
||||||
|
localforage.INDEXEDDB,
|
||||||
|
localforage.WEBSQL,
|
||||||
|
localforage.LOCALSTORAGE
|
||||||
|
]).then( () => {
|
||||||
|
localforage.setItem("state", ISOTerminal.prototype.convert.arrayBufferToBase64(state) )
|
||||||
|
console.log("state saved")
|
||||||
|
})
|
||||||
|
console.dir(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,30 +46,21 @@ if( typeof emulator != 'undefined' ){
|
||||||
localforage.getItem("state", async (err,stateBase64) => {
|
localforage.getItem("state", async (err,stateBase64) => {
|
||||||
if( stateBase64 && !err && confirm('continue last session?') ){
|
if( stateBase64 && !err && confirm('continue last session?') ){
|
||||||
this.noboot = true // see feat/boot.js
|
this.noboot = true // see feat/boot.js
|
||||||
state = this.convert.base64ToArrayBuffer( stateBase64 )
|
try{
|
||||||
|
await this.worker['emulator.restore_state']()
|
||||||
this.addEventListener('state_restored', function(){
|
|
||||||
// simulate / fastforward boot events
|
// simulate / fastforward boot events
|
||||||
this.postBoot( () => {
|
this.postBoot( () => {
|
||||||
this.send("l\n")
|
this.send("l\n")
|
||||||
this.send("hook wakeup\n")
|
this.send("hook wakeup\n")
|
||||||
})
|
})
|
||||||
})
|
}catch(e){ console.error(e) }
|
||||||
|
|
||||||
this.worker.postMessage({event:'emulator.restore_state',data:state})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.save = async () => {
|
this.save = async () => {
|
||||||
const state = await this.worker.postMessage({event:"emulator.save_state",data:false})
|
await this.worker['emulator.save_state']()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.addEventListener('state_saved', function(e){
|
|
||||||
const state = e.detail
|
|
||||||
localforage.setItem("state", this.convert.arrayBufferToBase64(state) )
|
|
||||||
console.log("state saved")
|
|
||||||
})
|
|
||||||
|
|
||||||
window.addEventListener("beforeunload", function (e) {
|
window.addEventListener("beforeunload", function (e) {
|
||||||
var confirmationMessage = "Sure you want to leave?\nTIP: enter 'save' to continue this session later";
|
var confirmationMessage = "Sure you want to leave?\nTIP: enter 'save' to continue this session later";
|
||||||
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
|
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
|
||||||
|
|
|
@ -4,7 +4,11 @@ ISOTerminal.addEventListener('ready', function(e){
|
||||||
|
|
||||||
ISOTerminal.prototype.boot = async function(e){
|
ISOTerminal.prototype.boot = async function(e){
|
||||||
// set environment
|
// set environment
|
||||||
let env = ['export BROWSER=1']
|
let env = [
|
||||||
|
`export LINES=${this.opts.rows}`,
|
||||||
|
`export COLUMNS=${this.opts.cols}`,
|
||||||
|
'export BROWSER=1',
|
||||||
|
]
|
||||||
for ( let i in document.location ){
|
for ( let i in document.location ){
|
||||||
if( typeof document.location[i] == 'string' ){
|
if( typeof document.location[i] == 'string' ){
|
||||||
env.push( 'export '+String(i).toUpperCase()+'="'+decodeURIComponent( document.location[i]+'"') )
|
env.push( 'export '+String(i).toUpperCase()+'="'+decodeURIComponent( document.location[i]+'"') )
|
||||||
|
|
Loading…
Reference in New Issue