diff --git a/com/isoterminal.js b/com/isoterminal.js
index c4ab4fe..dc42a01 100644
--- a/com/isoterminal.js
+++ b/com/isoterminal.js
@@ -1,32 +1,33 @@
-function ISOTerminal(instance,opts){
- // create a neutral isoterminal object which can be decorated
- // with prototype functions and has addListener() and dispatchEvent()
- let obj = new EventTarget()
- obj.instance = instance
- obj.opts = opts
- // register default event listeners (enable file based features like isoterminal/jsconsole.js e.g.)
- for( let event in ISOTerminal.listener )
- for( let cb in ISOTerminal.listener[event] )
- obj.addEventListener( event, ISOTerminal.listener[event][cb] )
- // compose object with functions
- for( let i in ISOTerminal.prototype ) obj[i] = ISOTerminal.prototype[i]
- obj.emit('init')
- return obj
-}
-
-ISOTerminal.prototype.emit = function(event,data){
- data = data || false
- this.dispatchEvent( new CustomEvent(event, {detail: data} ) )
-}
-
-ISOTerminal.addEventListener = (event,cb) => {
- ISOTerminal.listener = ISOTerminal.listener || {}
- ISOTerminal.listener[event] = ISOTerminal.listener[event] || []
- ISOTerminal.listener[event].push(cb)
-}
-
-// ISOTerminal has defacto support for AFRAME
-// but can be decorated to work without it as well
+/*
+ *
+ * css/html template
+ *
+ * ┌─────────┐ ┌────────────┐ ┌─────────────┐ exit-AR
+ * ┌───────►│ com/dom ┼──►│ com/window ├─►│ domrenderer │◄────────── exit-VR ◄─┐
+ * │ └─────────┘ └────────────┘ └─────▲───────┘ │
+ * │ │ ┌───────────────┐ │
+ * ┌──────────┴────────┐ ┌─────┴──────┐ │ xterm.js │ ┌─────────────────────────────┐
+ * │ com/isoterminal ├────────────────────────────►│com/xterm.js│◄─┤ │ │com/html-as-texture-in-XR.js │
+ * └────────┬─┬────────┘ └──┬──────┬▲─┘ │ xterm.css │ └─────────────────────────────┘
+ * │ │ ┌────────┐ ┌─────────▼──┐ ││ └───────────────┘ │ ▲
+ * │ └───────►│ plane ├─────►text───┼►canvas │◄────────────────── enter-VR │ │
+ * │ └────────┘ └────────────┘ ││ enter-AR ◄─┘ │
+ * │ ││ │
+ * │ ││ │
+ * │ ISOTerminal.js ││ │
+ * │ ┌───────────────────────────┐◄────┘│ │
+ * │ │ com/isoterminal/worker.js ├──────┘ │
+ * │ └──────────────┌────────────┤ │
+ * │ │ v86.js │ │
+ * │ │ feat/*.js │ │
+ * │ │ libv86.js │ │
+ * │ └────────────┘ │
+ * │ │
+ * └────────────────────────────────────────────────────────────────────────────────────┘
+ *
+ * NOTE: For convenience reasons, events are forwarded between com/isoterminal.js, worker.js and ISOTerminal
+ * Instead of a melting pot of different functionnames, events are flowing through everything (ISOTerminal.emit())
+ */
if( typeof AFRAME != 'undefined '){
@@ -68,14 +69,7 @@ if( typeof AFRAME != 'undefined '){
// html to texture
htmlinxr: "com/html-as-texture-in-xr.js",
// isoterminal features
- core: "com/isoterminal/core.js",
- utils_9p: "com/isoterminal/feat/9pfs_utils.js",
- boot: "com/isoterminal/feat/boot.js",
- jsconsole: "com/isoterminal/feat/jsconsole.js",
- 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",
+ ISOTerminal: "com/isoterminal/ISOTerminal.js",
localforage: "https://cdn.rawgit.com/mozilla/localForage/master/dist/localforage.js"
},
@@ -83,9 +77,6 @@ if( typeof AFRAME != 'undefined '){
scale: 0.66,
events: ['click','keydown'],
html: (me) => `
`,
css: (me) => `.isoterminal{
@@ -112,7 +103,8 @@ if( typeof AFRAME != 'undefined '){
overflow: hidden;
}
.isoterminal *,
- .xterm-dom-renderer-owner-1 .xterm-rows {
+ .isotemrinal .xterm-dom-renderer-owner-1 .xterm-rows {
+ background:transparent !important;
font-size: 14px;
font-family: "Cousine",Liberation Mono,DejaVu Sans Mono,Courier New,monospace;
font-weight:500 !important;
@@ -122,6 +114,11 @@ if( typeof AFRAME != 'undefined '){
.isoterminal style{ display:none }
+ #overlay .winbox:has(> .isoterminal){
+ background:transparent;
+ box-shadow:none;
+ }
+
.wb-body:has(> .isoterminal){
background: #000C;
overflow:hidden;
@@ -135,6 +132,11 @@ if( typeof AFRAME != 'undefined '){
.isoterminal div{ display:block; }
.isoterminal span{ display: inline }
+ .isoterminal .xterm-helpers {
+ position:absolute;
+ opacity:0;
+ }
+
@keyframes fade {
from { opacity: 1.0; }
50% { opacity: 0.5; }
@@ -158,13 +160,27 @@ if( typeof AFRAME != 'undefined '){
initTerminal: async function(singleton){
if( this.data.xterm ){
- 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.xterm = "com/isoterminal/feat/xterm.js"
- // xterm relies on window.requestAnimationFrame which is not called in XR (xrSession.requestAnimationFrame is)
+ // why 3.12?
+ // first versions used 1.5.4, a typescript rewrite which:
+ // * does not use canvas anymore [which would be ideal for THREE.js texture]
+ // * does not allow switching between dom/canvas
+ // * only allows a standalone WebGL addon (conflicts with THREE)
+ // * heavily dependent on requestAnimationFrame (conflicts with THREE)
+ // * typescript-rewrite results in ~300k lib (instead of 96k)
+ this.requires.xtermcss = "//unpkg.com/xterm@3.12.0/dist/xterm.css",
+ this.requires.xtermjs = "//unpkg.com/xterm@3.12.0/dist/xterm.js",
+ this.requires.xtermcss = "com/xterm.js"
}
- let s = await AFRAME.utils.require(this.requires)
+ await AFRAME.utils.require(this.requires)
+ await AFRAME.utils.require({ // ISOTerminal plugins
+ boot: "com/isoterminal/feat/boot.js",
+ javascript: "com/isoterminal/feat/javascript.js",
+ jsconsole: "com/isoterminal/feat/jsconsole.js",
+ //indexhtml: "com/isoterminal/feat/index.html.js",
+ //indexjs: "com/isoterminal/feat/index.js.js",
+ //autorestore: "com/isoterminal/feat/autorestore.js",
+ })
this.el.setAttribute("selfcontainer","")
@@ -194,10 +210,12 @@ if( typeof AFRAME != 'undefined '){
instance.addEventListener('window.oncreate', (e) => {
instance.dom.classList.add('blink')
+ instance.setAttribute("xterm","")
+ instance.addEventListener("xterm-input", (e) => this.isoterminal.send(e.detail,0) )
// run iso
let opts = {dom:instance.dom}
for( let i in this.data ) opts[i] = this.data[i]
- this.isoterminal.runISO(opts)
+ this.isoterminal.start(opts)
})
instance.setAttribute("dom", "")
@@ -214,9 +232,6 @@ if( typeof AFRAME != 'undefined '){
this.isoterminal.addEventListener('ready', (e)=>{
instance.dom.classList.remove('blink')
this.isoterminal.emit('status',"running")
- setTimeout( () => { // important: after window maximize animation to get true size
- instance.setAttribute("html-as-texture-in-xr", `domid: #${instance.uid}`) // only show aframe-html in xr
- },1500)
})
this.isoterminal.addEventListener('status', function(e){
@@ -236,8 +251,8 @@ if( typeof AFRAME != 'undefined '){
instance.addEventListener('window.onmaximize', resize )
const focus = (e) => {
- if( this.isoterminal?.emulator?.serial_adapter?.term ){
- this.isoterminal.emulator.serial_adapter.term.focus()
+ if( this.el.components.xterm ){
+ this.el.components.xterm.term.focus()
}
}
instance.addEventListener('obbcollisionstarted', focus )
@@ -257,10 +272,6 @@ if( typeof AFRAME != 'undefined '){
// reactive events for this.data updates
myvalue: function(e){ this.el.dom.querySelector('b').innerText = this.data.myvalue },
- ready: function( ){
- this.el.dom.style.display = 'none'
- },
-
launcher: async function(){
this.initTerminal()
}
diff --git a/com/isoterminal/core.js b/com/isoterminal/ISOTerminal.js
similarity index 100%
rename from com/isoterminal/core.js
rename to com/isoterminal/ISOTerminal.js
diff --git a/com/isoterminal/feat/9pfs_utils.js b/com/isoterminal/feat/9pfs_utils.js
index 737bcaf..9232530 100644
--- a/com/isoterminal/feat/9pfs_utils.js
+++ b/com/isoterminal/feat/9pfs_utils.js
@@ -1,46 +1,47 @@
-ISOTerminal.addEventListener('emulator-started', function(){
- let emulator = this.emulator
- let isoterminal = this
+let emulator = this.emulator
- emulator.fs9p.update_file = async function(file,data){
+emulator.fs9p.update_file = async function(file,data){
+ const convert = ISOTerminal.prototype.convert
- const p = this.SearchPath(file);
+ const p = this.SearchPath(file);
- if(p.id === -1)
- {
- return emulator.create_file(file,data)
- }
-
- const inode = this.GetInode(p.id);
- const buf = typeof data == 'string' ? isoterminal.convert.toUint8Array(data) : data
- await this.Write(p.id,0, buf.length, buf )
- // update inode
- inode.size = buf.length
- const now = Math.round(Date.now() / 1000);
- inode.atime = inode.mtime = now;
- isoterminal.exec(`touch ${file}`) // update inode
- return new Promise( (resolve,reject) => resolve(buf) )
+ if(p.id === -1)
+ {
+ return emulator.create_file(file,data)
+ }
+
+ const inode = this.GetInode(p.id);
+ const buf = typeof data == 'string' ? convert.toUint8Array(data) : data
+ await this.Write(p.id,0, buf.length, buf )
+ // update inode
+ inode.size = buf.length
+ const now = Math.round(Date.now() / 1000);
+ inode.atime = inode.mtime = now;
+ this.postMessage({event:'exec',data:[`touch ${file}`]}) // update inode
+ return new Promise( (resolve,reject) => resolve(buf) )
- }
+}
- emulator.fs9p.append_file = async function(file,data){
+emulator.fs9p.append_file = async function(file,data){
+ const convert = ISOTerminal.prototype.convert
- const p = this.SearchPath(file);
+ const p = this.SearchPath(file);
- if(p.id === -1)
- {
- return Promise.resolve(null);
- }
-
- const inode = this.GetInode(p.id);
- const buf = typeof data == 'string' ? isoterminal.convert.toUint8Array(data) : data
- await this.Write(p.id, inode.size, buf.length, buf )
- // update inode
- inode.size = inode.size + buf.length
- const now = Math.round(Date.now() / 1000);
- inode.atime = inode.mtime = now;
- return new Promise( (resolve,reject) => resolve(buf) )
+ if(p.id === -1)
+ {
+ return Promise.resolve(null);
+ }
+
+ const inode = this.GetInode(p.id);
+ const buf = typeof data == 'string' ? convert.toUint8Array(data) : data
+ await this.Write(p.id, inode.size, buf.length, buf )
+ // update inode
+ inode.size = inode.size + buf.length
+ const now = Math.round(Date.now() / 1000);
+ inode.atime = inode.mtime = now;
+ return new Promise( (resolve,reject) => resolve(buf) )
- }
+}
-})
+this['fs9p.append_file'] = function(){ emulator.fs9p.append_file.apply(emulator.fs9p, arguments[0]) }
+this['fs9p.update_file'] = function(){ emulator.fs9p.update_file.apply(emulator.fs9p, arguments[0]) }
diff --git a/com/isoterminal/feat/autorestore.js b/com/isoterminal/feat/autorestore.js
index db4df13..39ac2fa 100644
--- a/com/isoterminal/feat/autorestore.js
+++ b/com/isoterminal/feat/autorestore.js
@@ -1,4 +1,5 @@
ISOTerminal.addEventListener('emulator-started', function(e){
+ return console.log("TODO: autorestore.js")
this.autorestore(e)
})
diff --git a/com/isoterminal/feat/boot.js b/com/isoterminal/feat/boot.js
index 0f48172..d2267d8 100644
--- a/com/isoterminal/feat/boot.js
+++ b/com/isoterminal/feat/boot.js
@@ -6,10 +6,11 @@ ISOTerminal.prototype.boot = async function(e){
// set environment
let env = ['export BROWSER=1']
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]+'"') )
+ }
}
- await this.emulator.create_file("profile.browser", this.convert.toUint8Array( env.join('\n') ) )
+ await this.emit("emulator.create_file", ["profile.browser", this.convert.toUint8Array( env.join('\n') ) ] )
if( this.serial_input == 0 ){
if( !this.noboot ){
@@ -18,10 +19,5 @@ ISOTerminal.prototype.boot = async function(e){
}
}
- if( this.emulator.serial_adapter ) this.emulator.serial_adapter.term.focus()
- else{
- let els = [...document.querySelectorAll("div#screen")]
- els.map( (el) => el.focus() )
- }
}
diff --git a/com/isoterminal/feat/javascript.js b/com/isoterminal/feat/javascript.js
index f2b981a..f7deb93 100644
--- a/com/isoterminal/feat/javascript.js
+++ b/com/isoterminal/feat/javascript.js
@@ -1,29 +1,32 @@
-ISOTerminal.addEventListener('init', function(){
+if( typeof emulator != 'undefined' ){
+ // inside worker-thread
- this.addEventListener('emulator-started', function(e){
-
- const emulator = this.emulator
-
- // unix to js device
- this.readFromPipe( '/mnt/js', async (data) => {
- const buf = await emulator.read_file("js")
- const script = this.convert.Uint8ArrayToString(buf)
- let PID="?"
- try{
- if( script.match(/^PID/) ){
- PID = script.match(/^PID=([0-9]+);/)[1]
- }
- let res = (new Function(`${script}`))()
- if( res && typeof res != 'string' ) res = JSON.stringify(res,null,2)
- // write output to 9p with PID as filename
- // *FIXME* not flexible / robust
- emulator.create_file(PID, this.convert.toUint8Array(res) )
- }catch(e){
- console.error(e)
+ // unix to js device
+ emulator.readFromPipe( 'dev/browser/js', async (data) => {
+ const convert = ISOTerminal.prototype.convert
+ const buf = await this.emulator.read_file("dev/browser/js")
+ const script = convert.Uint8ArrayToString(buf)
+ let PID="?"
+ try{
+ if( script.match(/^PID/) ){
+ PID = script.match(/^PID=([0-9]+);/)[1]
}
- })
+ this.postMessage({event:'javascript-eval',data:{script,PID}})
+ }catch(e){
+ console.error(e)
+ }
+ })
+
+}else{
+ // inside browser-thread
- })
-
-})
+ ISOTerminal.addEventListener('javascript-eval', function(e){
+ const {script,PID} = e.detail
+ let res = (new Function(`${script}`))()
+ if( res && typeof res != 'string' ) res = JSON.stringify(res,null,2)
+ // write output to 9p with PID as filename
+ // *FIXME* not flexible / robust
+ this.emit('emulator.create_file', [PID, this.convert.toUint8Array(res)] )
+ })
+}
diff --git a/com/isoterminal/feat/jsconsole.js b/com/isoterminal/feat/jsconsole.js
index fcb64c1..3075c20 100644
--- a/com/isoterminal/feat/jsconsole.js
+++ b/com/isoterminal/feat/jsconsole.js
@@ -27,7 +27,6 @@ ISOTerminal.prototype.redirectConsole = function(handler){
}
ISOTerminal.addEventListener('emulator-started', function(){
- let emulator = this.emulator
this.redirectConsole( (str,prefix) => {
let finalStr = ""
@@ -35,7 +34,7 @@ ISOTerminal.addEventListener('emulator-started', function(){
str.trim().split("\n").map( (line) => {
finalStr += '\x1b[38;5;165m/dev/browser: \x1b[0m'+prefix+line+'\n'
})
- emulator.fs9p.append_file( "console", finalStr )
+ this.emit('fs9p.append_file', ["/dev/browser/console",finalStr])
})
window.addEventListener('error', function(event) {
@@ -51,9 +50,4 @@ ISOTerminal.addEventListener('emulator-started', function(){
console.error(event);
});
- // enable/disable logging file (echo 1 > mnt/console.tty)
- this.readFromPipe( '/mnt/console.tty', (data) => {
- emulator.log_to_tty = ( String(data).trim() == '1')
- })
-
})
diff --git a/com/isoterminal/feat/xterm.js b/com/isoterminal/feat/xterm.js
index 592f559..70bcb52 100644
--- a/com/isoterminal/feat/xterm.js
+++ b/com/isoterminal/feat/xterm.js
@@ -27,7 +27,6 @@ ISOTerminal.prototype.xtermInit = function(){
})
term.onRender( () => {
-
// xterm relies on requestAnimationFrame (which does not called in immersive mode)
let _window = term._core._coreBrowserService._window
if( !_window._XRSH_proxied ){ // patch the planet!
@@ -40,8 +39,10 @@ ISOTerminal.prototype.xtermInit = function(){
// term.tid = null
// },100)
//}
+ this.i = 0
const requestAnimationFrameAFRAME = AFRAME.utils.throttleLeadingAndTrailing(
- function(cb){ cb() },150
+ function(cb){ cb() }
+ ,150
)
// we proxy the _window object of xterm, and reroute
diff --git a/com/isoterminal/worker.js b/com/isoterminal/worker.js
new file mode 100644
index 0000000..d0a8315
--- /dev/null
+++ b/com/isoterminal/worker.js
@@ -0,0 +1,78 @@
+importScripts("libv86.js");
+importScripts("ISOTerminal.js") // we don't instance it again here (just use its functions)
+
+//var emulator = new V86({
+// wasm_path: "../build/v86.wasm",
+// memory_size: 32 * 1024 * 1024,
+// vga_memory_size: 2 * 1024 * 1024,
+// bios: {
+// url: "../bios/seabios.bin",
+// },
+// vga_bios: {
+// url: "../bios/vgabios.bin",
+// },
+// cdrom: {
+// url: "../images/linux4.iso",
+// },
+// autostart: true,
+//});
+//
+//
+//emulator.add_listener("serial0-output-byte", function(byte)
+//{
+// var chr = String.fromCharCode(byte);
+// this.postMessage(chr);
+//}.bind(this));
+//
+//this.onmessage = function(e)
+//{
+// emulator.serial0_send(e.data);
+//};
+
+this.runISO = function(opts){
+ if( opts.cdrom ) opts.cdrom.url = "../../"+opts.cdrom.url
+ if( opts.bzimage ) opts.bzimage.url = "../../"+opts.bzimage.url
+
+ let emulator = this.emulator = new V86(opts);
+ console.log("worker:started emulator")
+
+ // event forwarding
+ emulator.add_listener("serial0-output-byte", function(byte){
+ this.postMessage({event:"serial0-output-byte",data:byte});
+ }.bind(this));
+
+ emulator.add_listener("emulator-started", function(){
+ importScripts("feat/9pfs_utils.js")
+ this.postMessage({event:"emulator-started",data:false});
+ }.bind(this));
+
+ /*
+ * forward events/functions so non-worker world can reach them
+ */
+ this['emulator.create_file'] = function(){ emulator.create_file.apply(emulator, arguments[0]) }
+ this['emulator.read_file'] = function(){ emulator.read_file.apply(emulator, arguments[0]) }
+
+
+ // filename will be read from 9pfs: "/mnt/"+filename
+ emulator.readFromPipe = function(filename,cb){
+ emulator.add_listener("9p-write-end", async (opts) => {
+ if ( opts[0] == filename.replace(/.*\//,'') ){
+ cb()
+ }
+ })
+ }
+
+ importScripts("feat/javascript.js")
+}
+/*
+ * forward events/functions so non-worker world can reach them
+ */
+
+this['serial0-input'] = function(c){
+ this.emulator.bus.send( 'serial0-input', c)
+}
+
+this.onmessage = function(e){
+ let {event,data} = e.data
+ if( this[event] ) this[event](data)
+}
diff --git a/com/xterm.js b/com/xterm.js
new file mode 100644
index 0000000..f81c986
--- /dev/null
+++ b/com/xterm.js
@@ -0,0 +1,175 @@
+let terminalInstance = 0
+
+const TERMINAL_THEME = {
+ theme_foreground: {
+ // 'default': '#ffffff'
+ },
+ theme_background: {
+ // 'default': '#000'
+ },
+ theme_cursor: {
+ // 'default': '#ffffff'
+ },
+ theme_selection: {
+ // 'default': 'rgba(255, 255, 255, 0.3)'
+ },
+ theme_black: {
+ // 'default': '#000000'
+ },
+ theme_red: {
+ // 'default': '#e06c75'
+ },
+ theme_brightRed: {
+ // 'default': '#e06c75'
+ },
+ theme_green: {
+ // 'default': '#A4EFA1'
+ },
+ theme_brightGreen: {
+ // 'default': '#A4EFA1'
+ },
+ theme_brightYellow: {
+ // 'default': '#EDDC96'
+ },
+ theme_yellow: {
+ // 'default': '#EDDC96'
+ },
+ theme_magenta: {
+ // 'default': '#e39ef7'
+ },
+ theme_brightMagenta: {
+ // 'default': '#e39ef7'
+ },
+ theme_cyan: {
+ // 'default': '#5fcbd8'
+ },
+ theme_brightBlue: {
+ // 'default': '#5fcbd8'
+ },
+ theme_brightCyan: {
+ // 'default': '#5fcbd8'
+ },
+ theme_blue: {
+ // 'default': '#5fcbd8'
+ },
+ theme_white: {
+ // 'default': '#d0d0d0'
+ },
+ theme_brightBlack: {
+ // 'default': '#808080'
+ },
+ theme_brightWhite: {
+ // 'default': '#ffffff'
+ }
+}
+
+AFRAME.registerComponent('xterm', {
+ schema: Object.assign({
+ cols: {
+ type: 'number',
+ default: 110,
+ },
+ rows: {
+ type: 'number',
+ default: Math.floor( (window.innerHeight * 0.7 ) * 0.054 )
+ },
+ }, TERMINAL_THEME),
+
+ write: function(message) {
+ this.term.write(message)
+ },
+ init: function () {
+ const terminalElement = document.createElement('div')
+ terminalElement.setAttribute('style', `
+ width: ${Math.floor( window.innerWidth * 0.7 )}px;
+ height: ${Math.floor( window.innerHeight * 0.7 )}px;
+ overflow: hidden;
+ `)
+
+ this.el.dom.appendChild(terminalElement)
+ //document.body.appendChild(terminalElement)
+ this.el.terminalElement = terminalElement
+
+ // Build up a theme object
+ const theme = Object.keys(this.data).reduce((theme, key) => {
+ if (!key.startsWith('theme_')) return theme
+ const data = this.data[key]
+ if(!data) return theme
+ theme[key.slice('theme_'.length)] = data
+ return theme
+ }, {})
+
+ this.renderType = 'dom'
+
+ const term = new Terminal({
+ theme: theme,
+ allowTransparency: true,
+ cursorBlink: true,
+ disableStdin: false,
+ rows: this.data.rows,
+ cols: this.data.cols,
+ fontSize: 14,
+ lineHeight: 1.15,
+ rendererType: this.renderType
+ })
+
+ this.term = term
+
+ term.open(terminalElement)
+ term.focus()
+
+ terminalElement.querySelector('.xterm-viewport').style.background = 'transparent'
+
+ ////// now we can scale canvases to the parent element
+ const $screen = terminalElement.querySelector('.xterm-screen')
+ $screen.style.width = '100%'
+
+ term.on('refresh', () => {
+ if( this.renderType == 'canvas' ){
+ const material = this.el.getObject3D('mesh').material
+ if (!material.map) return
+ this.canvasContext.drawImage(this.cursorCanvas, 0,0)
+ material.map.needsUpdate = true
+ }
+ })
+
+ term.on('data', (data) => {
+ this.el.emit('xterm-input', data)
+ })
+
+ this.el.addEventListener('click', () => {
+ term.focus()
+ })
+
+ this.el.addEventListener('serial-output-byte', (e) => {
+ const byte = e.detail
+ var chr = String.fromCharCode(byte);
+ this.term.write(chr)
+ })
+
+ this.el.addEventListener('serial-output-string', (e) => this.term.write(e.detail) )
+
+ },
+
+ setRenderType: function(type){
+
+ if( type.match(/(dom|canvas)/) ){
+
+ if( type == 'dom'){
+ this.el.removeAttribute('material')
+ }
+
+ term.setOption('rendererType',type )
+ this.renderType = type
+
+ if( type == 'canvas'){
+ this.canvas = terminalElement.querySelector('.xterm-text-layer')
+ this.canvasContext = this.canvas.getContext('2d')
+ this.cursorCanvas = terminalElement.querySelector('.xterm-cursor-layer')
+ this.el.setAttribute('material', 'transparent', true)
+ this.el.setAttribute('material', 'src', '#' + this.canvas.id)
+ }
+ }
+ },
+
+})