tweaks for fbterm
This commit is contained in:
parent
e8d6d0a8c1
commit
4125f90f06
|
@ -35,8 +35,8 @@ if( typeof AFRAME != 'undefined '){
|
|||
schema: {
|
||||
iso: { type:"string", "default":"https://forgejo.isvery.ninja/assets/xrsh-buildroot/main/xrsh.iso" },
|
||||
overlayfs: { type:"string"},
|
||||
width: { type: 'number',"default": 700 },
|
||||
height: { type: 'number',"default": 500 },
|
||||
width: { type: 'number',"default": 800 },
|
||||
height: { type: 'number',"default": 600 },
|
||||
depth: { type: 'number',"default": 0.03 },
|
||||
lineHeight: { type: 'number',"default": 18 },
|
||||
padding: { type: 'number',"default": 18 },
|
||||
|
@ -46,9 +46,9 @@ if( typeof AFRAME != 'undefined '){
|
|||
HUD: { type: 'boolean',"default":false}, // link to camera movement
|
||||
transparent: { type:'boolean', "default":false }, // need good gpu
|
||||
memory: { type: 'number', "default":60 }, // VM memory (in MB) [NOTE: quest or smartphone might crash > 40mb ]
|
||||
bufferLatency: { type: 'number', "default":1 }, // 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 },
|
||||
emulator: { type: 'string', "default": "vt100" }
|
||||
emulator: { type: 'string', "default": "fbterm" }// terminal emulator
|
||||
},
|
||||
|
||||
init: function(){
|
||||
|
@ -59,7 +59,6 @@ if( typeof AFRAME != 'undefined '){
|
|||
|
||||
this.calculateDimension()
|
||||
this.initHud()
|
||||
this.setupBox()
|
||||
this.setupPasteDrop()
|
||||
|
||||
fetch(this.data.iso,{method: 'HEAD'})
|
||||
|
@ -94,26 +93,18 @@ if( typeof AFRAME != 'undefined '){
|
|||
scale: 0.66,
|
||||
events: ['click','keydown'],
|
||||
html: (me) => `<div class="isoterminal">
|
||||
<div style="white-space: pre;"></div>
|
||||
<canvas style="display: none"></canvas>
|
||||
<div id="term" tabindex="0">
|
||||
<pre></pre>
|
||||
</div>
|
||||
<input type="file" id="pastedrop" style="position:absolute; left:-9999px;opacity:0"></input>
|
||||
<div id="term" tabindex="0"></div>
|
||||
</div>`,
|
||||
|
||||
css: (me) => `.isoterminal{
|
||||
css: (me) => `
|
||||
|
||||
.isoterminal{
|
||||
padding: ${me.com.data.padding}px;
|
||||
width:100%;
|
||||
height:90%;
|
||||
position:relative;
|
||||
}
|
||||
.isoterminal div{
|
||||
display:block;
|
||||
position:relative;
|
||||
line-height: ${me.com.data.lineHeight}px;
|
||||
}
|
||||
#term {
|
||||
outline: none !important;
|
||||
height:99%;
|
||||
resize: both;
|
||||
overflow: hidden;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Cousine';
|
||||
|
@ -128,6 +119,73 @@ if( typeof AFRAME != 'undefined '){
|
|||
src: url(./com/isoterminal/assets/CousineBold.ttf) format('truetype');
|
||||
}
|
||||
|
||||
.isoterminal *{
|
||||
outline:none;
|
||||
box-shadow:none;
|
||||
}
|
||||
|
||||
.term {
|
||||
font-family: 'Cousine';
|
||||
line-height: ${me.com.data.lineHeight}px;
|
||||
font-weight: normal;
|
||||
font-variant-ligatures: none;
|
||||
color: #f0f0f0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.term_content a {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
color:#2AFF;
|
||||
}
|
||||
|
||||
.term_content a span{
|
||||
text-shadow: 0px 0px 10px #F07A;
|
||||
}
|
||||
|
||||
.term_content a:hover {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
animation:fade 1000ms infinite;
|
||||
-webkit-animation:fade 1000ms infinite;
|
||||
}
|
||||
|
||||
.term_cursor {
|
||||
color: #000000;
|
||||
background: #70f;
|
||||
animation:fade 1000ms infinite;
|
||||
-webkit-animation:fade 1000ms infinite;
|
||||
}
|
||||
|
||||
.term_char_size {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: -1000px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.term_textarea {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
margin: 0px;
|
||||
opacity: 0;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.term_scrollbar { background: transparent url(images/bg-scrollbar-track-y.png) no-repeat 0 0; position: relative; background-position: 0 0; float: right; height: 100%; }
|
||||
.term_track { background: transparent url(images/bg-scrollbar-trackend-y.png) no-repeat 0 100%; height: 100%; width:13px; position: relative; padding: 0 1px; }
|
||||
.term_thumb { background: transparent url(images/bg-scrollbar-thumb-y.png) no-repeat 50% 100%; height: 20px; width: 25px; cursor: pointer; overflow: hidden; position: absolute; top: 0; left: -5px; }
|
||||
.term_thumb .term_end { background: transparent url(images/bg-scrollbar-thumb-y.png) no-repeat 50% 0; overflow: hidden; height: 5px; width: 25px; }
|
||||
.noSelect { user-select: none; -o-user-select: none; -moz-user-select: none; -khtml-user-select: none; -webkit-user-select: none; }
|
||||
|
||||
.isoterminal style{ display:none }
|
||||
|
||||
blink{
|
||||
|
@ -140,12 +198,6 @@ if( typeof AFRAME != 'undefined '){
|
|||
box-shadow:none;
|
||||
}
|
||||
|
||||
.cursor {
|
||||
background: #70F !important;
|
||||
animation:fade 1000ms infinite;
|
||||
-webkit-animation:fade 1000ms infinite;
|
||||
}
|
||||
|
||||
.XR .cursor {
|
||||
animation:none;
|
||||
-webkit-animation:none;
|
||||
|
@ -214,10 +266,10 @@ if( typeof AFRAME != 'undefined '){
|
|||
pastedropFeat: "com/isoterminal/feat/pastedrop.js",
|
||||
httpfs: "com/isoterminal/feat/httpfs.js",
|
||||
}
|
||||
if( this.data.emulator == "vt100" ){
|
||||
features['VT100js'] = "com/isoterminal/VT100.js"
|
||||
features['vt100'] = "com/isoterminal/feat/vt100.js"
|
||||
}
|
||||
if( this.data.emulator == 'fbterm' ){
|
||||
features['fbtermjs'] = "com/isoterminal/term.js"
|
||||
features['fbterm'] = "com/isoterminal/feat/term.js"
|
||||
}
|
||||
await AFRAME.utils.require(features)
|
||||
|
||||
this.el.setAttribute("selfcontainer","")
|
||||
|
@ -325,25 +377,14 @@ if( typeof AFRAME != 'undefined '){
|
|||
return this
|
||||
},
|
||||
|
||||
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 = Math.floor( document.body.offsetHeight - 30 )
|
||||
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*2)
|
||||
this.rows = Math.floor( (this.data.height*0.93)/this.data.lineHeight)
|
||||
this.cols = Math.floor(this.data.width/this.data.lineHeight*2)-1
|
||||
this.rows = Math.floor( (this.data.height*0.93)/this.data.lineHeight)-1
|
||||
},
|
||||
|
||||
events:{
|
||||
|
|
|
@ -34,11 +34,12 @@ ISOTerminal.addEventListener = (event,cb) => {
|
|||
}
|
||||
|
||||
ISOTerminal.prototype.exec = function(shellscript){
|
||||
this.send(shellscript+"\n",1)
|
||||
this.send(`printf "\n\r"; ${shellscript}\n`,1)
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.hook = function(hookname,args){
|
||||
this.exec(`{ type hook || source /etc/profile.sh; }; hook ${hookname} "${args.join('" "')}"`)
|
||||
let cmd = `{ type hook || source /etc/profile.sh; }; hook ${hookname} "${args.join('" "')}"`
|
||||
this.exec(cmd)
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.serial_input = 0; // can be set to 0,1,2,3 to define stdinput tty (xterm plugin)
|
||||
|
@ -53,7 +54,7 @@ ISOTerminal.prototype.send = function(str, ttyNr){
|
|||
this.convert.toUint8Array( str ).map( (c) => {
|
||||
this.preventFrameDrop(
|
||||
() => {
|
||||
this.worker.postMessage({event:`serial${ttyNr}-input`,data:c})
|
||||
this.worker.postMessage({event:`serial${ttyNr}-input`,data:c})
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -189,15 +190,14 @@ ISOTerminal.prototype.startVM = function(opts){
|
|||
|
||||
const empower = [
|
||||
"FOSS gives users control over their software, offering freedom to modify and share",
|
||||
"Feeling powerless with tech? FOSS escapes a mindset known as learned helplessness",
|
||||
"Feeling powerless? FOSS escapes a mindset known as learned helplessness",
|
||||
"FOSS breaks this cycle by showing that anyone can learn and contribute",
|
||||
"Proprietary software can make users dependent, but FOSS offers real choices",
|
||||
"FOSS communities provide support and encourage users to develop new skills",
|
||||
"Learned helplessness fades when we realize tech isn’t too complex to understand",
|
||||
"FOSS empowers users to customize and improve their tools",
|
||||
"Engaging with FOSS helps build confidence and self-reliance in tech",
|
||||
"FOSS shows that anyone can shape the digital world with curiosity and effort",
|
||||
"Linux can revive old computers, extending their life and reducing e-waste",
|
||||
"Linux can revive old computers, extending their life and reduces e-waste",
|
||||
"Many lightweight Linux distributions run smoothly on older hardware",
|
||||
"Installing Linux on aging devices keeps them functional instead of sending them to the landfill",
|
||||
"Linux uses fewer resources, making it ideal for reusing older machines",
|
||||
|
@ -216,16 +216,17 @@ ISOTerminal.prototype.startVM = function(opts){
|
|||
\r[38;5;129m . . . / \\ | | \\/ \\ Y / .
|
||||
\r[38;5;165m . . ./___/\\ \\ |____|_ /_______ /\\___|_ /. .
|
||||
\r[38;5;201m . . . . . .\\_/. . . . \\/ . . . .\\/ . . _ \\/ . .
|
||||
\r[38;5;165m ▬▬▬▬▬▬▬▬ https://xrsh.isvery.ninja ▬▬▬▬▬▬▬▬▬▬▬▬
|
||||
\r[38;5;165m ▬▬▬▬▬▬▬▬ [38;5;51mhttps://xrsh.isvery.ninja[38;5;165m ▬▬▬▬▬▬▬▬▬▬▬▬
|
||||
\r[38;5;165m local-first, polyglot, unixy WebXR IDE & runtime
|
||||
\r
|
||||
\r[38;5;57m
|
||||
\r credits
|
||||
\r -------
|
||||
\r @nlnet@nlnet.nl
|
||||
\r @lvk@mastodon.online
|
||||
\r @utopiah@mastodon.pirateparty.be
|
||||
\r @utopiah@mastodon.pirateparty.be [38;5;51m
|
||||
\r https://www.w3.org/TR/webxr
|
||||
\r https://three.org
|
||||
\r https://xrfragment.org
|
||||
\r https://threejs.org
|
||||
\r https://aframe.org
|
||||
\r https://busybox.net
|
||||
\r https://buildroot.org
|
||||
|
@ -233,7 +234,7 @@ ISOTerminal.prototype.startVM = function(opts){
|
|||
|
||||
const text_color = "\r[38;5;129m"
|
||||
const text_reset = "\033[0m"
|
||||
const loadmsg = "\n\r "+loading[ Math.floor(Math.random()*1000) % loading.length ] + "..[please wait]"
|
||||
const loadmsg = "\n\r "+loading[ Math.floor(Math.random()*1000) % loading.length ] + "..please wait"
|
||||
const empowermsg = "\n\r "+text_reset+'"'+empower[ Math.floor(Math.random()*1000) % empower.length ] + '"\n\r'
|
||||
this.emit('status',loadmsg)
|
||||
this.emit('serial-output-string', motd + empowermsg + text_color + loadmsg + text_reset+"\n\r")
|
||||
|
|
|
@ -14,7 +14,7 @@ ISOTerminal.prototype.boot = async function(e){
|
|||
env.push( 'export '+String(i).toUpperCase()+'="'+decodeURIComponent( document.location[i]+'"') )
|
||||
}
|
||||
}
|
||||
this.worker.create_file("profile.browser", this.convert.toUint8Array( env.join('\n') ) )
|
||||
await this.worker.create_file("profile.browser", this.convert.toUint8Array( env.join('\n') ) )
|
||||
|
||||
if( this.serial_input == 0 ){
|
||||
if( !this.noboot ){
|
||||
|
|
|
@ -17,7 +17,7 @@ if( typeof emulator != 'undefined' ){
|
|||
ISOTerminal.prototype.pasteFile = async function(data){
|
||||
const {type,item,pastedText} = data
|
||||
if( pastedText){
|
||||
this.pasteWriteFile( this.convert.toUint8Array(pastedText) ,type)
|
||||
this.pasteWriteFile( this.convert.toUint8Array(pastedText) ,type, null, true)
|
||||
}else{
|
||||
const file = item.getAsFile();
|
||||
const reader = new FileReader();
|
||||
|
@ -29,4 +29,18 @@ if( typeof emulator != 'undefined' ){
|
|||
}
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.pasteInit = function(opts){
|
||||
// bind upload input
|
||||
const {instance, aEntity} = opts
|
||||
const el = aEntity.el.dom.querySelector('#pastedrop') // upload input
|
||||
el.addEventListener('change', (e) => {
|
||||
const file = el.files[0];
|
||||
const item = {...file, getAsFile: () => file }
|
||||
this.el.emit('pasteFile', { item, type: file.type });
|
||||
})
|
||||
}
|
||||
|
||||
ISOTerminal.addEventListener('init', function(){
|
||||
this.addEventListener('term_init', (opts) => this.pasteInit(opts.detail) )
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
ISOTerminal.addEventListener('init', function(){
|
||||
this.TermInit()
|
||||
})
|
||||
|
||||
ISOTerminal.prototype.TermInit = function(){
|
||||
|
||||
const setupTerm = (opts) => {
|
||||
if( !opts ) return
|
||||
const {instance, aEntity} = opts
|
||||
const el = aEntity.el.dom.querySelector('#term')
|
||||
opts.termOpts = {
|
||||
cols: aEntity.cols,
|
||||
rows: aEntity.rows,
|
||||
el_or_id: el,
|
||||
scrollback: aEntity.rows*3,
|
||||
fontSize: null //
|
||||
//rainbow: [Term.COLOR_MAGENTA, Term.COLOR_CYAN ],
|
||||
//xr: AFRAME.scenes[0].renderer.xr,
|
||||
//map: {
|
||||
// 'ArrowRight': { ch: false, ctrl: '\x1b\x66' }, // this triggers ash-shell forward-word
|
||||
// 'ArrowLeft': { ch: false, ctrl: '\x1b\x62' } // backward-word
|
||||
//}
|
||||
}
|
||||
|
||||
// patch Term-class
|
||||
Term.prototype.move_textarea = function(){} /* *TODO* *FIXME* does not work in winbox */
|
||||
|
||||
Term.prototype.pasteHandler = function(original){
|
||||
return function (ev){
|
||||
original.apply(this,[ev])
|
||||
}
|
||||
}( Term.prototype.pasteHandler )
|
||||
|
||||
Term.prototype.keyDownHandler = function(original){
|
||||
return function (e){
|
||||
if ((e.ctrlKey || e.metaKey) && e.key === 'v') {
|
||||
return true; // bubble up to pasteHandler (see pastedrop.js)
|
||||
}
|
||||
original.apply(this,[e])
|
||||
}
|
||||
}( Term.prototype.keyDownHandler )
|
||||
|
||||
Term.prototype.href = (a) => {
|
||||
if( a.href ){
|
||||
this.exec(`source /etc/profile.sh; hook href "${a.href}"`)
|
||||
}
|
||||
return false
|
||||
}
|
||||
this.term = new Term( opts.termOpts )
|
||||
this.term.colors = [
|
||||
/* normal */
|
||||
"#000000",
|
||||
"#2FA",
|
||||
"#7700ff",
|
||||
"#555555",
|
||||
"#0000ff",
|
||||
"#aa00aa",
|
||||
"#ff00aa",
|
||||
"#aaaaaa",
|
||||
/* bright */
|
||||
"#555555",
|
||||
"#ff5555",
|
||||
"#2CF",
|
||||
"#aa00ff",
|
||||
"#5555ff",
|
||||
"#ff55ff",
|
||||
"#55ffff",
|
||||
"#ffffff"
|
||||
];
|
||||
this.term.open(el)
|
||||
this.term.el = el
|
||||
|
||||
this.term.setKeyHandler( (ch) => this.send(ch) )
|
||||
aEntity.el.addEventListener('focus', () => el.querySelector("textarea").focus() )
|
||||
aEntity.el.addEventListener('serial-output-string', (e) => {
|
||||
this.term.write(e.detail)
|
||||
})
|
||||
//aEntity.term.emit('initTerm',this)
|
||||
//aEntity.el.addEventListener('focus', () => this.vt100.focus() )
|
||||
|
||||
//aEntity.el.addEventListener('serial-output-string', (e) => {
|
||||
// this.vt100.write(e.detail)
|
||||
//})
|
||||
|
||||
}
|
||||
|
||||
this.addEventListener('term_init', (opts) => setupTerm(opts.detail) )
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue