added restore + requestAnimationFrameXR to mitigate requestAnimationFrame issues
/ test (push) Successful in 5s
Details
/ test (push) Successful in 5s
Details
This commit is contained in:
parent
10c274fdd4
commit
f75f34d6a6
|
@ -1,3 +1,5 @@
|
|||
if( AFRAME.components.codemirror ) delete AFRAME.components.codemirror
|
||||
|
||||
AFRAME.registerComponent('codemirror', {
|
||||
schema: {
|
||||
foo: { type:"string"}
|
||||
|
@ -16,7 +18,6 @@ AFRAME.registerComponent('codemirror', {
|
|||
|
||||
requires:{
|
||||
window: "com/window.js",
|
||||
htmltexture: "com/html-as-texture-in-xr.js",
|
||||
codemirror: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/codemirror.js",
|
||||
codemirrorcss: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/codemirror.css",
|
||||
cmtheme: "https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.35.0/theme/shadowfox.css"
|
||||
|
@ -31,6 +32,13 @@ AFRAME.registerComponent('codemirror', {
|
|||
css: (me) => `.codemirror{
|
||||
width:100%;
|
||||
}
|
||||
.codemirror *{
|
||||
font-size: 14px;
|
||||
font-family: "Cousine",Liberation Mono,DejaVu Sans Mono,Courier New,monospace;
|
||||
font-weight:500 !important;
|
||||
letter-spacing: 0 !important;
|
||||
text-shadow: 0px 0px 10px #F075;
|
||||
}
|
||||
.wb-body + .codemirror{ overflow:hidden; }
|
||||
.CodeMirror {
|
||||
margin-top:18px;
|
||||
|
@ -47,7 +55,6 @@ AFRAME.registerComponent('codemirror', {
|
|||
DOMready: function(e){
|
||||
console.log(`title: codemirror; uid: ${this.el.dom.id}; attach: #overlay; dom: #${this.el.dom.id};`)
|
||||
this.el.setAttribute("window", `title: codemirror; uid: ${this.el.dom.id}; attach: #overlay; dom: #${this.el.dom.id};`)
|
||||
this.el.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}`) // only show aframe-html in xr
|
||||
this.editor = CodeMirror( this.el.dom, {
|
||||
value: "function myScript(){return 100;}\n",
|
||||
mode: "javascript",
|
||||
|
@ -61,6 +68,9 @@ AFRAME.registerComponent('codemirror', {
|
|||
}
|
||||
})
|
||||
this.editor.setOption("theme", "shadowfox")
|
||||
setTimeout( () => {
|
||||
this.el.setAttribute("html-as-texture-in-xr", `domid: #${this.el.dom.id}`) // only show aframe-html in xr
|
||||
},1500)
|
||||
},
|
||||
},
|
||||
|
||||
|
|
13
com/dom.js
13
com/dom.js
|
@ -36,6 +36,10 @@ if( !AFRAME.components.dom ){
|
|||
|
||||
AFRAME.registerComponent('dom',{
|
||||
|
||||
requires: {
|
||||
"requestAnimationFrameXR": "com/requestAnimationFrameXR.js"
|
||||
},
|
||||
|
||||
init: function(){
|
||||
Object.values(this.el.components)
|
||||
.map( (c) => {
|
||||
|
@ -127,12 +131,9 @@ if( !AFRAME.components.dom ){
|
|||
return this
|
||||
},
|
||||
|
||||
stubRequestAnimationFrame: function(){
|
||||
// stub, because WebXR with overrule this (it will not call the callback as expected in immersive mode)
|
||||
const requestAnimationFrame = window.requestAnimationFrame
|
||||
window.requestAnimationFrame = (cb) => {
|
||||
setTimeout( cb, 25 )
|
||||
}
|
||||
stubRequestAnimationFrame: async function(){
|
||||
let s = await AFRAME.utils.require(this.requires)
|
||||
this.el.setAttribute("requestAnimationFrameXR","")
|
||||
}
|
||||
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
if( !AFRAME.components['html-as-textre-in-xr'] ){
|
||||
if( !AFRAME.components['html-as-texture-in-xr'] ){
|
||||
|
||||
AFRAME.registerComponent('html-as-texture-in-xr', {
|
||||
schema: {
|
||||
|
@ -12,6 +12,10 @@ if( !AFRAME.components['html-as-textre-in-xr'] ){
|
|||
},
|
||||
|
||||
init: async function () {
|
||||
let el = document.querySelector(this.data.domid)
|
||||
if( ! el ){
|
||||
return console.error("html-as-texture-in-xr: cannot get dom element "+this.data.dom.id)
|
||||
}
|
||||
let s = await AFRAME.utils.require(this.dependencies)
|
||||
this.el.setAttribute("html",`html: ${this.data.domid}; cursor:#cursor; xrlayer: true`)
|
||||
this.el.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' )
|
||||
|
|
|
@ -37,10 +37,11 @@ if( typeof AFRAME != 'undefined '){
|
|||
cols: { type: 'number',"default": 120 },
|
||||
rows: { type: 'number',"default": 30 },
|
||||
padding: { type: 'number',"default": 18 },
|
||||
minimized: { type: 'boolean',"default":false},
|
||||
maximized: { type: 'boolean',"default":true},
|
||||
transparent: { type:'boolean', "default":false }, // need good gpu
|
||||
xterm: { type: 'boolean', "default":true }, // use xterm.js (slower)
|
||||
memory: { type: 'number', "default":32 } // VM memory (in MB)
|
||||
memory: { type: 'number', "default":48 } // VM memory (in MB)
|
||||
},
|
||||
|
||||
init: async function(){
|
||||
|
@ -74,6 +75,8 @@ if( typeof AFRAME != 'undefined '){
|
|||
javascript: "com/isoterminal/feat/javascript.js",
|
||||
indexhtml: "com/isoterminal/feat/index.html.js",
|
||||
indexjs: "com/isoterminal/feat/index.js.js",
|
||||
autorestore: "com/isoterminal/feat/autorestore.js",
|
||||
localforage: "https://cdn.rawgit.com/mozilla/localForage/master/dist/localforage.js"
|
||||
},
|
||||
|
||||
dom: {
|
||||
|
@ -90,16 +93,26 @@ if( typeof AFRAME != 'undefined '){
|
|||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Cousine';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(./assets/Cousine.ttf) format('truetype');
|
||||
}
|
||||
.isoterminal *{
|
||||
white-space: pre;
|
||||
font-size: 14px;
|
||||
font-family: Liberation Mono,DejaVu Sans Mono,Courier New,monospace;
|
||||
font-weight:900 !important;
|
||||
letter-spacing: 0 !important;
|
||||
line-height:16px;
|
||||
display:inline;
|
||||
overflow: hidden;
|
||||
}
|
||||
.isoterminal *,
|
||||
.xterm-dom-renderer-owner-1 .xterm-rows {
|
||||
font-size: 14px;
|
||||
font-family: "Cousine",Liberation Mono,DejaVu Sans Mono,Courier New,monospace;
|
||||
font-weight:500 !important;
|
||||
letter-spacing: 0 !important;
|
||||
text-shadow: 0px 0px 10px #F075;
|
||||
}
|
||||
|
||||
.isoterminal style{ display:none }
|
||||
|
||||
|
@ -108,6 +121,10 @@ if( typeof AFRAME != 'undefined '){
|
|||
overflow:hidden;
|
||||
}
|
||||
|
||||
.XR .wb-body:has(> .isoterminal){
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.isoterminal div{ display:block; }
|
||||
.isoterminal span{ display: inline }
|
||||
|
||||
|
@ -163,7 +180,7 @@ if( typeof AFRAME != 'undefined '){
|
|||
//instance.winbox.resize(720,380)
|
||||
let size = this.data.xterm ? 'width: 1024px; height:600px'
|
||||
: 'width: 720px; height:455px'
|
||||
instance.setAttribute("window", `title: xrsh.iso; uid: ${instance.uid}; attach: #overlay; dom: #${instance.dom.id}; ${size}`)
|
||||
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.addEventListener('window.oncreate', (e) => {
|
||||
|
@ -179,8 +196,11 @@ if( typeof AFRAME != 'undefined '){
|
|||
|
||||
this.isoterminal.addEventListener('postReady', (e)=>{
|
||||
// bugfix: send window dimensions to xterm (xterm.js does that from dom-sizechange to xterm via escape codes)
|
||||
if( this.data.maximized ) instance.winbox.maximize()
|
||||
else instance.winbox.resize()
|
||||
let wb = instance.winbox
|
||||
if( this.data.maximized ){
|
||||
wb.restore()
|
||||
wb.maximize()
|
||||
}else wb.resize()
|
||||
})
|
||||
|
||||
this.isoterminal.addEventListener('ready', (e)=>{
|
||||
|
@ -208,11 +228,12 @@ if( typeof AFRAME != 'undefined '){
|
|||
instance.addEventListener('window.onmaximize', resize )
|
||||
|
||||
const focus = (e) => {
|
||||
if( this.isoterminal?.emulator?.serial_adapter?.focus ){
|
||||
if( this.isoterminal?.emulator?.serial_adapter?.term ){
|
||||
this.isoterminal.emulator.serial_adapter.term.focus()
|
||||
}
|
||||
}
|
||||
//instance.addEventListener('obbcollisionstarted', focus )
|
||||
instance.addEventListener('obbcollisionstarted', focus )
|
||||
|
||||
this.el.sceneEl.addEventListener('enter-vr', focus )
|
||||
this.el.sceneEl.addEventListener('enter-ar', focus )
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ ISOTerminal.prototype.runISO = function(opts){
|
|||
uart3:true, // /dev/ttyS3
|
||||
wasm_path: "com/isoterminal/v86.wasm",
|
||||
memory_size: opts.memory * 1024 * 1024,
|
||||
vga_memory_size: 1024, //2 * 1024 * 1024,
|
||||
vga_memory_size: 2 * 1024 * 1024,
|
||||
screen_container: opts.dom,
|
||||
//serial_container: opts.dom,
|
||||
bios: {
|
||||
|
@ -145,8 +145,8 @@ ISOTerminal.prototype.runISO = function(opts){
|
|||
line += chr;
|
||||
}
|
||||
if( !ready && line.match(/^(\/ #|~%|\[.*\]>)/) ){
|
||||
this.emit('postReady')
|
||||
setTimeout( () => this.emit('ready'), 500 )
|
||||
this.emit('postReady',e)
|
||||
setTimeout( () => this.emit('ready',e), 500 )
|
||||
ready = true
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
ISOTerminal.addEventListener('emulator-started', function(e){
|
||||
this.autorestore(e)
|
||||
})
|
||||
|
||||
ISOTerminal.prototype.convert = {
|
||||
|
||||
arrayBufferToBase64: function(buffer){
|
||||
let binary = '';
|
||||
const bytes = new Uint8Array(buffer);
|
||||
const len = bytes.byteLength;
|
||||
for (let i = 0; i < len; i++) binary += String.fromCharCode(bytes[i]);
|
||||
return window.btoa(binary);
|
||||
},
|
||||
|
||||
base64ToArrayBuffer: function(base64) {
|
||||
const binaryString = window.atob(base64);
|
||||
const len = binaryString.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
return bytes.buffer;
|
||||
}
|
||||
}
|
||||
|
||||
ISOTerminal.prototype.autorestore = async function(e){
|
||||
|
||||
localforage.setDriver([
|
||||
localforage.INDEXEDDB,
|
||||
localforage.WEBSQL,
|
||||
localforage.LOCALSTORAGE
|
||||
]).then( () => {
|
||||
|
||||
localforage.getItem("state", (err,stateBase64) => {
|
||||
if( !err && confirm('continue last session?') ){
|
||||
this.noboot = true // see feat/boot.js
|
||||
state = this.convert.base64ToArrayBuffer( stateBase64 )
|
||||
this.emulator.restore_state(state)
|
||||
this.emit('postReady',e)
|
||||
setTimeout( () => {
|
||||
this.emit('ready',e)
|
||||
this.send("alert last session restored\n")
|
||||
}, 500 )
|
||||
}
|
||||
})
|
||||
|
||||
this.save = async () => {
|
||||
const state = await this.emulator.save_state()
|
||||
console.log( String(this.convert.arrayBufferToBase64(state)).substr(0,5) )
|
||||
localforage.setItem("state", this.convert.arrayBufferToBase64(state) )
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
ISOTerminal.addEventListener('ready', function(){
|
||||
this.boot()
|
||||
ISOTerminal.addEventListener('ready', function(e){
|
||||
setTimeout( () => this.boot(), 50 ) // because of autorestore.js
|
||||
})
|
||||
|
||||
ISOTerminal.prototype.boot = async function(){
|
||||
ISOTerminal.prototype.boot = async function(e){
|
||||
// set environment
|
||||
let env = ['export BROWSER=1']
|
||||
for ( let i in document.location ){
|
||||
|
@ -10,10 +10,13 @@ ISOTerminal.prototype.boot = async function(){
|
|||
env.push( 'export '+String(i).toUpperCase()+'="'+document.location[i]+'"')
|
||||
}
|
||||
await this.emulator.create_file("profile.browser", this.toUint8Array( env.join('\n') ) )
|
||||
|
||||
if( this.serial_input == 0 ){
|
||||
if( !this.noboot ){
|
||||
let boot = "source /etc/profile\n"
|
||||
this.send(boot+"\n")
|
||||
}
|
||||
}
|
||||
|
||||
if( this.emulator.serial_adapter ) this.emulator.serial_adapter.term.focus()
|
||||
else{
|
||||
|
|
|
@ -16,9 +16,7 @@ ISOTerminal.prototype.xtermInit = function(){
|
|||
window.Terminal = function(opts){
|
||||
const term = new window._Terminal({ ...opts,
|
||||
cursorBlink:true,
|
||||
onSelectionChange: function(e){
|
||||
debugger
|
||||
},
|
||||
onSelectionChange: function(e){ console.log("selectchange") },
|
||||
letterSpacing: 0
|
||||
})
|
||||
|
||||
|
@ -38,7 +36,7 @@ ISOTerminal.prototype.xtermInit = function(){
|
|||
|
||||
const resize = (w,h) => {
|
||||
setTimeout( () => {
|
||||
isoterm.xtermAutoResize(isoterm.emulator.serial_adapter.term, isoterm.instance,-2)
|
||||
isoterm.xtermAutoResize(isoterm.emulator.serial_adapter.term, isoterm.instance,-3)
|
||||
},800) // wait for resize anim
|
||||
}
|
||||
isoterm.instance.addEventListener('window.onresize', resize )
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* ## 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
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
}
|
|
@ -7,6 +7,7 @@ AFRAME.registerComponent('window', {
|
|||
attach: {type:'selector'},
|
||||
dom: {type:'selector'},
|
||||
max: {type:'boolean',"default":false},
|
||||
min: {type:'boolean',"default":false},
|
||||
x: {type:'string',"default":"center"},
|
||||
y: {type:'string',"default":"center"}
|
||||
},
|
||||
|
@ -35,6 +36,7 @@ AFRAME.registerComponent('window', {
|
|||
root: this.data.attach || document.body,
|
||||
mount: this.data.dom,
|
||||
max: this.data.max,
|
||||
min: this.data.min,
|
||||
onresize: () => this.el.emit('window.onresize',{}),
|
||||
onmaximize: () => this.el.emit('window.onmaximize',{}),
|
||||
oncreate: (e) => {
|
||||
|
|
Loading…
Reference in New Issue