xterm repaint improvements (still not great)
This commit is contained in:
parent
44f79ac02a
commit
9d69ef9c57
|
@ -59,7 +59,6 @@ if( !AFRAME.components.dom ){
|
||||||
.assignUniqueID()
|
.assignUniqueID()
|
||||||
.scaleDOMvsXR()
|
.scaleDOMvsXR()
|
||||||
.triggerKeyboardForInputs()
|
.triggerKeyboardForInputs()
|
||||||
.stubRequestAnimationFrame()
|
|
||||||
|
|
||||||
document.querySelector('#overlay').appendChild(this.el.dom)
|
document.querySelector('#overlay').appendChild(this.el.dom)
|
||||||
this.el.emit('DOMready',{el: this.el.dom})
|
this.el.emit('DOMready',{el: this.el.dom})
|
||||||
|
@ -131,10 +130,5 @@ if( !AFRAME.components.dom ){
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
|
|
||||||
stubRequestAnimationFrame: async function(){
|
|
||||||
let s = await AFRAME.utils.require(this.requires)
|
|
||||||
this.el.setAttribute("requestAnimationFrameXR","")
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,13 @@ if( typeof AFRAME != 'undefined '){
|
||||||
rows: { type: 'number',"default": 30 },
|
rows: { type: 'number',"default": 30 },
|
||||||
padding: { type: 'number',"default": 18 },
|
padding: { type: 'number',"default": 18 },
|
||||||
minimized: { type: 'boolean',"default":false},
|
minimized: { type: 'boolean',"default":false},
|
||||||
maximized: { type: 'boolean',"default":true},
|
maximized: { type: 'boolean',"default":false},
|
||||||
transparent: { type:'boolean', "default":false }, // need good gpu
|
transparent: { type:'boolean', "default":false }, // need good gpu
|
||||||
xterm: { type: 'boolean', "default":true }, // use xterm.js? (=slower)
|
xterm: { type: 'boolean', "default":true }, // use xterm.js? (=slower)
|
||||||
memory: { type: 'number', "default":48 } // VM memory (in MB)
|
memory: { type: 'number', "default":48 } // VM memory (in MB)
|
||||||
},
|
},
|
||||||
|
|
||||||
init: async function(){
|
init: function(){
|
||||||
this.el.object3D.visible = false
|
this.el.object3D.visible = false
|
||||||
fetch(this.data.iso,{method: 'HEAD'})
|
fetch(this.data.iso,{method: 'HEAD'})
|
||||||
.then( (res) => {
|
.then( (res) => {
|
||||||
|
@ -125,6 +125,7 @@ if( typeof AFRAME != 'undefined '){
|
||||||
.wb-body:has(> .isoterminal){
|
.wb-body:has(> .isoterminal){
|
||||||
background: #000C;
|
background: #000C;
|
||||||
overflow:hidden;
|
overflow:hidden;
|
||||||
|
border-radius:7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.XR .wb-body:has(> .isoterminal){
|
.XR .wb-body:has(> .isoterminal){
|
||||||
|
@ -159,6 +160,7 @@ if( typeof AFRAME != 'undefined '){
|
||||||
this.requires.xtermjs = "https://unpkg.com/@xterm/xterm@5.5.0/lib/xterm.js"
|
this.requires.xtermjs = "https://unpkg.com/@xterm/xterm@5.5.0/lib/xterm.js"
|
||||||
this.requires.xtermcss = "https://unpkg.com/@xterm/xterm@5.5.0/css/xterm.css"
|
this.requires.xtermcss = "https://unpkg.com/@xterm/xterm@5.5.0/css/xterm.css"
|
||||||
this.requires.xterm = "com/isoterminal/feat/xterm.js"
|
this.requires.xterm = "com/isoterminal/feat/xterm.js"
|
||||||
|
// xterm relies on window.requestAnimationFrame which is not called in XR (xrSession.requestAnimationFrame is)
|
||||||
}
|
}
|
||||||
|
|
||||||
let s = await AFRAME.utils.require(this.requires)
|
let s = await AFRAME.utils.require(this.requires)
|
||||||
|
@ -199,7 +201,6 @@ if( typeof AFRAME != 'undefined '){
|
||||||
|
|
||||||
instance.setAttribute("dom", "")
|
instance.setAttribute("dom", "")
|
||||||
|
|
||||||
|
|
||||||
this.isoterminal.addEventListener('postReady', (e)=>{
|
this.isoterminal.addEventListener('postReady', (e)=>{
|
||||||
// bugfix: send window dimensions to xterm (xterm.js does that from dom-sizechange to xterm via escape codes)
|
// bugfix: send window dimensions to xterm (xterm.js does that from dom-sizechange to xterm via escape codes)
|
||||||
let wb = instance.winbox
|
let wb = instance.winbox
|
||||||
|
@ -246,7 +247,6 @@ if( typeof AFRAME != 'undefined '){
|
||||||
instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera
|
instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
events:{
|
events:{
|
||||||
|
|
||||||
// combined AFRAME+DOM reactive events
|
// combined AFRAME+DOM reactive events
|
||||||
|
|
|
@ -25,9 +25,30 @@ ISOTerminal.prototype.xtermInit = function(){
|
||||||
term.select(0, 0, 0)
|
term.select(0, 0, 0)
|
||||||
isoterm.emit('status','copied to clipboard')
|
isoterm.emit('status','copied to clipboard')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
term.onRender( () => {
|
||||||
|
console.log("render")
|
||||||
|
// xterm relies on requestAnimationFrame (which does not called in immersive mode)
|
||||||
|
const _window = term._core._coreBrowserService._window
|
||||||
|
const requestAnimationFrame = _window.requestAnimationFrame
|
||||||
|
// luckily xterm allows a swappable window object
|
||||||
|
let newWindow = function(){}.bind(window)
|
||||||
|
for( var i in window ) newWindow[i] = window[i]
|
||||||
|
newWindow.requestAnimationFrame = (cb) => {
|
||||||
|
if( term.tid != null ) return
|
||||||
|
setTimeout( () => {
|
||||||
|
cb()
|
||||||
|
term.tid = null
|
||||||
|
},200)
|
||||||
|
}
|
||||||
|
term._core._coreBrowserService._window = newWindow
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
return term
|
return term
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.addEventListener('emulator-started', function(){
|
this.addEventListener('emulator-started', function(){
|
||||||
this.emulator.serial_adapter.term.element.querySelector('.xterm-viewport').style.background = 'transparent'
|
this.emulator.serial_adapter.term.element.querySelector('.xterm-viewport').style.background = 'transparent'
|
||||||
// toggle immersive with ESCAPE
|
// toggle immersive with ESCAPE
|
||||||
|
@ -36,7 +57,9 @@ ISOTerminal.prototype.xtermInit = function(){
|
||||||
|
|
||||||
const resize = (w,h) => {
|
const resize = (w,h) => {
|
||||||
setTimeout( () => {
|
setTimeout( () => {
|
||||||
|
if( isoterm?.emulator?.serial_adapter?.term ){
|
||||||
isoterm.xtermAutoResize(isoterm.emulator.serial_adapter.term, isoterm.instance,-3)
|
isoterm.xtermAutoResize(isoterm.emulator.serial_adapter.term, isoterm.instance,-3)
|
||||||
|
}
|
||||||
},800) // wait for resize anim
|
},800) // wait for resize anim
|
||||||
}
|
}
|
||||||
isoterm.instance.addEventListener('window.onresize', resize )
|
isoterm.instance.addEventListener('window.onresize', resize )
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* ## requestAnimationFrameXR
|
|
||||||
*
|
|
||||||
* reroutes requestAnimationFrame-calls to xrSession.requestAnimationFrame
|
|
||||||
* reason: in immersive mode this function behaves differently
|
|
||||||
* (causing HTML apps like xterm.js not getting updated due to relying
|
|
||||||
* on window.requestAnimationFrame)
|
|
||||||
*
|
|
||||||
* ```html
|
|
||||||
* <a-entity requestAnimationFrameXR dom/>
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
|
|
||||||
if( !AFRAME.systems.requestAnimationFrameXR ){
|
|
||||||
|
|
||||||
AFRAME.registerSystem('requestAnimationFrameXR',{
|
|
||||||
|
|
||||||
init: function init(){
|
|
||||||
if( document.location.hostname.match(/localhost/) ) return // allow webxr polyfill during development (they hang in XR)
|
|
||||||
AFRAME.systems.requestAnimationFrameXR.q = []
|
|
||||||
this.sceneEl.addEventListener('enter-vr', this.enable )
|
|
||||||
this.sceneEl.addEventListener('enter-ar', this.enable )
|
|
||||||
this.sceneEl.addEventListener('exit-vr', this.disable )
|
|
||||||
this.sceneEl.addEventListener('exit-ar', this.disable )
|
|
||||||
},
|
|
||||||
|
|
||||||
enable: function enable(){
|
|
||||||
this.requestAnimationFrame = window.requestAnimationFrame
|
|
||||||
// NOTE: we don't call xrSession.requestAnimationFrame directly like this:
|
|
||||||
//
|
|
||||||
// window.requestAnimationFrame = AFRAME.utils.throttleTick( (cb) => this.sceneEl.xrSession.requestAnimationFrame(cb), 50 )
|
|
||||||
//
|
|
||||||
// as that breaks webxr polyfill (for in-browser testing)
|
|
||||||
// instead we defer calls to tick() (which is called both in XR and non-XR)
|
|
||||||
//
|
|
||||||
window.requestAnimationFrame = (cb) => AFRAME.systems.requestAnimationFrameXR.q.push(cb)
|
|
||||||
const q = AFRAME.systems.requestAnimationFrameXR.q
|
|
||||||
this.tick = AFRAME.utils.throttleTick( () => {
|
|
||||||
while( q.length != 0 ) (q.pop())()
|
|
||||||
},50)
|
|
||||||
},
|
|
||||||
|
|
||||||
disable: function disable(){
|
|
||||||
delete this.tick
|
|
||||||
window.requestAnimationFrame = this.requestAnimationFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
AFRAME.registerComponent('xrfragments', {
|
|
||||||
schema: {
|
|
||||||
url: { type:"string"}
|
|
||||||
},
|
|
||||||
|
|
||||||
init: function () {
|
|
||||||
},
|
|
||||||
|
|
||||||
events:{
|
|
||||||
|
|
||||||
launcher: async function(){
|
|
||||||
let url = prompt('enter URL to glb/fbx/json/obj/usdz asset', 'https://xrfragment.org/index.glb')
|
|
||||||
if( !url ) return
|
|
||||||
await AFRAME.utils.require({
|
|
||||||
xrfragments: "https://xrfragment.org/dist/xrfragment.aframe.js",
|
|
||||||
})
|
|
||||||
|
|
||||||
// remove objects which are marked to be removed from scene (with noxrf)
|
|
||||||
let els = [...document.querySelectorAll('[noxrf]') ]
|
|
||||||
els.map( (el) => el.remove() )
|
|
||||||
|
|
||||||
if( !this.el.getAttribute("xrf") ){
|
|
||||||
this.el.setAttribute("xrf", url )
|
|
||||||
let ARbutton = document.querySelector('.a-enter-ar-button')
|
|
||||||
if( ARbutton ){
|
|
||||||
ARbutton.addEventListener('click', () => {
|
|
||||||
AFRAME.XRF.reset()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}else AFRAME.XRF.navigator.to(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
manifest: { // HTML5 manifest to identify app to xrsh
|
|
||||||
"short_name": "XRF",
|
|
||||||
"name": "XR Fragment URL",
|
|
||||||
"icons": [ ],
|
|
||||||
"id": "/?source=pwa",
|
|
||||||
"start_url": "/?source=pwa",
|
|
||||||
"background_color": "#3367D6",
|
|
||||||
"display": "standalone",
|
|
||||||
"scope": "/",
|
|
||||||
"theme_color": "#3367D6",
|
|
||||||
"shortcuts": [
|
|
||||||
{
|
|
||||||
"name": "What is the latest news?",
|
|
||||||
"cli":{
|
|
||||||
"usage": "helloworld <type> [options]",
|
|
||||||
"example": "helloworld news",
|
|
||||||
"args":{
|
|
||||||
"--latest": {type:"string"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"short_name": "Today",
|
|
||||||
"description": "View weather information for today",
|
|
||||||
"url": "/today?source=pwa",
|
|
||||||
"icons": [{ "src": "/images/today.png", "sizes": "192x192" }]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Hello world information",
|
|
||||||
"screenshots": [
|
|
||||||
{
|
|
||||||
"src": "/images/screenshot1.png",
|
|
||||||
"type": "image/png",
|
|
||||||
"sizes": "540x720",
|
|
||||||
"form_factor": "narrow"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"help":`
|
|
||||||
Helloworld application
|
|
||||||
|
|
||||||
This is a help file which describes the application.
|
|
||||||
It will be rendered thru troika text, and will contain
|
|
||||||
headers based on non-punctualized lines separated by linebreaks,
|
|
||||||
in above's case "\nHelloworld application\n" will qualify as header.
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
Loading…
Reference in New Issue