1st commit fabien's drumkeyboard
This commit is contained in:
		
							parent
							
								
									bc030e2669
								
							
						
					
					
						commit
						3b7ce6daab
					
				
					 11 changed files with 287 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -11,6 +11,7 @@
 | 
			
		|||
 | 
			
		||||
| package | description |
 | 
			
		||||
|-|-|
 | 
			
		||||
| [drumkeyboard](drumkeyboard) | A customizable keyboard component  |
 | 
			
		||||
| [fzy](fzy) | lightweight + fast fuzzyfinder alternative |
 | 
			
		||||
| [joe](joe) | Set of battleproof lightweight text/code editors |
 | 
			
		||||
| [nano](nano) | Lightweight code editor with syntax highlighting  |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								drumkeyboard/.env
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										18
									
								
								drumkeyboard/.env
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
dir=$(pwd)
 | 
			
		||||
 | 
			
		||||
# overlay our directories
 | 
			
		||||
run(){
 | 
			
		||||
	test -f /.nano || {
 | 
			
		||||
	  find . -type d -mindepth 1 | while read dir; do
 | 
			
		||||
	    cp -d -r ./$dir/* /$dir/.
 | 
			
		||||
	  done
 | 
			
		||||
	  echo 1 > /.nano
 | 
			
		||||
	  cp ./root/.nanorc ~/.
 | 
			
		||||
	  echo "[i] imported overlay fs"
 | 
			
		||||
	  echo "[i] editor 'nano' installed" | logger
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
test -n "$BROWSER" && run
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								drumkeyboard/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								drumkeyboard/README.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
# Drumkeyboard
 | 
			
		||||
 | 
			
		||||
A customizable keyboard component 
 | 
			
		||||
 | 
			
		||||
> NOTE: after importing package run `cd ~/scene-drumkeyboard` to load the demoscene
 | 
			
		||||
							
								
								
									
										4
									
								
								drumkeyboard/build.sh
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								drumkeyboard/build.sh
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
set -e
 | 
			
		||||
name=drumkeyboard
 | 
			
		||||
zip -r package.$name.zip root .env .env.leave
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								drumkeyboard/package.drumkeyboard.zip
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								drumkeyboard/package.drumkeyboard.zip
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										4
									
								
								drumkeyboard/root/scene-drumkeyboard/.env
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								drumkeyboard/root/scene-drumkeyboard/.env
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,4 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
echo "loading drumkeyboard demo scene"
 | 
			
		||||
cp index.html /root/index.html
 | 
			
		||||
cat drumkbd.js index.js > /root/index.js
 | 
			
		||||
							
								
								
									
										1
									
								
								drumkeyboard/root/scene-drumkeyboard/.env.leave
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								drumkeyboard/root/scene-drumkeyboard/.env.leave
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
echo "" > /root/index.html # cleanup
 | 
			
		||||
							
								
								
									
										229
									
								
								drumkeyboard/root/scene-drumkeyboard/drumkbd.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								drumkeyboard/root/scene-drumkeyboard/drumkbd.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,229 @@
 | 
			
		|||
// let sequentialFilters = []
 | 
			
		||||
// <script src="filters/keymap.js"></script>
 | 
			
		||||
 | 
			
		||||
let currentFilter = null
 | 
			
		||||
 | 
			
		||||
function applyNextFilter( filename ){
 | 
			
		||||
	if ( currentFilter == null ) currentFilter = -1
 | 
			
		||||
	currentFilter++
 | 
			
		||||
	if ( sequentialFilters[currentFilter] ){
 | 
			
		||||
		sequentialFilters[ currentFilter ]( filename )
 | 
			
		||||
	} else {
 | 
			
		||||
		console.log( "done filtering for", filename )
 | 
			
		||||
		currentFilter = null
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function showFile( filename, openingOptions = {}){
 | 
			
		||||
	console.log('showFile', filename)
 | 
			
		||||
	fetch( '/mnt/root/scene-drumkeyboard/'+filename ).then( r => {
 | 
			
		||||
		let idFromFilename = filename.replaceAll('.','') // has to remove from proper CSS ID
 | 
			
		||||
		if (!filesWithMetadata[filename] ) filesWithMetadata[filename] = {}
 | 
			
		||||
		filesWithMetadata[filename].contentType = r.headers.get('Content-Type')
 | 
			
		||||
		filesWithMetadata[filename].idFromFilename = idFromFilename
 | 
			
		||||
		filesWithMetadata[filename].openingOptions = openingOptions
 | 
			
		||||
		console.log( 'ct metadata', filename, filesWithMetadata[filename].contentType )
 | 
			
		||||
 | 
			
		||||
		applyNextFilter( filename )
 | 
			
		||||
		// const showdefinitions = urlParams.get('showdefinitions');
 | 
			
		||||
		// should be showFile() configuration parameter instead
 | 
			
		||||
                // can be used via e.g. showFile("https://fabien.benetou.fr/?action=source",{ mereology:"whole"})
 | 
			
		||||
 | 
			
		||||
		// should emit an event when done, for now just console.log which isn't programmatic
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function addDrumKeyboard(){
 | 
			
		||||
	// get keymap
 | 
			
		||||
	showFile('fabien_corneish_zen.keymap')
 | 
			
		||||
	// showFile('fabien_corneish_zen.keymap')
 | 
			
		||||
	
 | 
			
		||||
	const swiping = urlParams.get('swiping');
 | 
			
		||||
 | 
			
		||||
	const keyclass = "keys_from_drumsticks"
 | 
			
		||||
	// transform keymap to keys of keyboard
 | 
			
		||||
	let keyboardEl = document.createElement("a-entity")
 | 
			
		||||
	keyboardEl.id = 'keyboard'
 | 
			
		||||
	AFRAME.scenes[0].appendChild( keyboardEl )
 | 
			
		||||
	AFRAME.scenes[0].addEventListener("keymaploaded", e => {
 | 
			
		||||
		applyToClass("keymap_layer", el => el.setAttribute("visible", "false") )
 | 
			
		||||
		// alternatively other layers could be displayed but with lower opacity
 | 
			
		||||
			// might be very busy but easier to recall
 | 
			
		||||
		Array.from( document.querySelectorAll('.keymap_layer') ).map( (layerToAdd, layerNumber) => {
 | 
			
		||||
			layerToAdd.getAttribute("value").split('\n').map( (l,y) => {
 | 
			
		||||
				l.split("|").map( (k,x) => {
 | 
			
		||||
					if (k.trim()) {
 | 
			
		||||
						// zIndex could be once deep once shallow to potentially go faster between keys, kind of straggered vs ortho
 | 
			
		||||
						let xOffset = -.2
 | 
			
		||||
						let yOffset = 1.3
 | 
			
		||||
						let zOffset = -.4
 | 
			
		||||
						let keysPerRow = l.split("|").length -1
 | 
			
		||||
						let ratio = 1/20
 | 
			
		||||
						zOffset -= Math.abs( keysPerRow/2 - x ) * ratio/5 // arguably more ergonomic
 | 
			
		||||
						if (swiping){ zOffset = zOffset + Math.abs( x - keysPerRow/2 ) * ratio } // opposite from swiping 
 | 
			
		||||
						// somehow the center isn't... the center
 | 
			
		||||
						if (l.length < 70) xOffset += .15 // 80 was fine for layer 0 but not layer 1 and 2
 | 
			
		||||
						let labelEl = document.createElement("a-troika-text")
 | 
			
		||||
						labelEl.setAttribute("value",k.trim())
 | 
			
		||||
						labelEl.setAttribute("position", "0 .51 0")
 | 
			
		||||
						labelEl.setAttribute("font-size", "1")
 | 
			
		||||
						labelEl.setAttribute("color", "black")
 | 
			
		||||
						labelEl.setAttribute("rotation", "-90 0 0")
 | 
			
		||||
 | 
			
		||||
						let keyEl = document.createElement("a-cylinder")
 | 
			
		||||
						keyEl.setAttribute("segments-height", "2")
 | 
			
		||||
						keyEl.setAttribute("segments-radial", "24")
 | 
			
		||||
						keyEl.setAttribute("scale", ".01 .01 .01")
 | 
			
		||||
						keyEl.setAttribute("rotation", "60 0 0")
 | 
			
		||||
						keyEl.setAttribute("position", ""+(xOffset+x*ratio)+" " +(yOffset-y*ratio)+" "+(zOffset + y/50) )
 | 
			
		||||
						keyEl.classList.add( keyclass )
 | 
			
		||||
						keyEl.classList.add( "layer_"+ layerNumber )
 | 
			
		||||
						keyEl.appendChild( labelEl )
 | 
			
		||||
						keyboardEl.appendChild( keyEl )
 | 
			
		||||
						// keyEl.id = keyclass+'_'+k.trim() // not correct anymore as multiple layers can have the same key
 | 
			
		||||
						keyEl.id = keyclass+'_'+layerNumber+'_'+k.trim()  
 | 
			
		||||
						// setTimeout( _ => keyEl.object3D.lookAt( new THREE.Vector3(0, 1.5, 0)), 100 )
 | 
			
		||||
							// not great as they have 90 deg rotation already, could find a better way
 | 
			
		||||
							// ... but arguably should be the opposite based on resting hand positions
 | 
			
		||||
					}
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		keys_from_drumsticks_0_SHFT.setAttribute("wireframe", shiftFromVirtualKeyboard) // arguable, could do so for all layers
 | 
			
		||||
		// hide all layers but the current one
 | 
			
		||||
		Array.from( document.querySelectorAll(".keys_from_drumsticks") ).map( k => k.setAttribute("visible", "false") )
 | 
			
		||||
		Array.from( document.querySelectorAll(".keys_from_drumsticks"+".layer_"+layerFromVirtualKeyboard) ).map( k => k.setAttribute("visible", "true") )
 | 
			
		||||
		keyBoardCheck()
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	const threshold = .02 // distance
 | 
			
		||||
	const refractionPeriod = 500 // ms until next keypress
 | 
			
		||||
 | 
			
		||||
	// add visible contact points
 | 
			
		||||
	let jointTestEl1 = document.createElement("a-sphere")
 | 
			
		||||
	jointTestEl1.setAttribute("radius", .01)
 | 
			
		||||
	jointTestEl1.id = "jointtest1"
 | 
			
		||||
	AFRAME.scenes[0].appendChild( jointTestEl1 )
 | 
			
		||||
	let jointTestEl2 = document.createElement("a-sphere")
 | 
			
		||||
	jointTestEl2.setAttribute("radius", .01)
 | 
			
		||||
	jointTestEl2.id = "jointtest2"
 | 
			
		||||
	AFRAME.scenes[0].appendChild( jointTestEl2 )
 | 
			
		||||
	AFRAME.scenes[0].setAttribute("bind-element-to-finger__test1", { hand: 'r_handMeshNode', finger: 'index-finger-tip', target: '#jointtest1' } )
 | 
			
		||||
	AFRAME.scenes[0].setAttribute("bind-element-to-finger__test2", { hand: 'l_handMeshNode', finger: 'index-finger-tip', target: '#jointtest2' } )
 | 
			
		||||
 | 
			
		||||
	// thumb tip test
 | 
			
		||||
	let jointTestEl3 = document.createElement("a-sphere")
 | 
			
		||||
	jointTestEl3.setAttribute("radius", .01)
 | 
			
		||||
	jointTestEl3.id = "jointtest3"
 | 
			
		||||
	AFRAME.scenes[0].appendChild( jointTestEl3 )
 | 
			
		||||
	let jointTestEl4 = document.createElement("a-sphere")
 | 
			
		||||
	jointTestEl4.setAttribute("radius", .01)
 | 
			
		||||
	jointTestEl4.id = "jointtest4"
 | 
			
		||||
	AFRAME.scenes[0].appendChild( jointTestEl4 )
 | 
			
		||||
	AFRAME.scenes[0].setAttribute("bind-element-to-finger__test3", { hand: 'r_handMeshNode', finger: 'thumb-tip', target: '#jointtest3' } )
 | 
			
		||||
	AFRAME.scenes[0].setAttribute("bind-element-to-finger__test4", { hand: 'l_handMeshNode', finger: 'thumb-tip', target: '#jointtest4' } )
 | 
			
		||||
 | 
			
		||||
	const forcecontrollers = urlParams.get('forcecontrollers');
 | 
			
		||||
	if (forcecontrollers){
 | 
			
		||||
		setTimeout( _ => {
 | 
			
		||||
			jointtest1.object3D.parent = document.querySelector("[meta-touch-controls]").object3D
 | 
			
		||||
			jointtest2.object3D.parent = document.querySelector("[oculus-touch-controls]").object3D
 | 
			
		||||
		}, 2000 )
 | 
			
		||||
		// TODO does not work with pen
 | 
			
		||||
			// see <a-entity logiteck-mx-ink-controls="hand: right"></a-entity> that does not seem to show anything, even in AFrame 1.7.1 nor recent master build
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// if done a la bind-element-to-finger consider
 | 
			
		||||
		// const joint = AFRAME.scenes[0].object3D.getObjectByName(this.data.hand)?.parent.getObjectByName(this.data.finger)
 | 
			
		||||
		// if ( joint && this.data.target.object3D.parent == AFRAME.scenes[0].object3D ) this.data.target.object3D.parent = joint
 | 
			
		||||
 | 
			
		||||
	let pos1 = new THREE.Vector3()
 | 
			
		||||
	let pos2 = new THREE.Vector3()
 | 
			
		||||
	let pos3 = new THREE.Vector3()
 | 
			
		||||
	let pos4 = new THREE.Vector3()
 | 
			
		||||
 | 
			
		||||
	let shiftFromVirtualKeyboard = true
 | 
			
		||||
	let layerFromVirtualKeyboard = 0
 | 
			
		||||
 | 
			
		||||
	window.keyboardTarget = typinghud
 | 
			
		||||
 | 
			
		||||
	// check for potential contact
 | 
			
		||||
	let lastKeypress = Date.now()
 | 
			
		||||
	function keyBoardCheck() {
 | 
			
		||||
		 return setInterval( _ => {
 | 
			
		||||
			jointTestEl1.object3D.getWorldPosition( pos1 )
 | 
			
		||||
			jointTestEl2.object3D.getWorldPosition( pos2 )
 | 
			
		||||
			jointTestEl3.object3D.getWorldPosition( pos3 )
 | 
			
		||||
			jointTestEl4.object3D.getWorldPosition( pos4 )
 | 
			
		||||
			// could also check only when jointTestEl1 / jointTestEl2 are visible, ignore otherwise
 | 
			
		||||
 | 
			
		||||
			// to do with all keys instead
 | 
			
		||||
			Array.from( document.querySelectorAll(".keys_from_drumsticks"+".layer_"+layerFromVirtualKeyboard) )
 | 
			
		||||
			.concat( [keys_from_drumsticks_0_LWR, keys_from_drumsticks_0_RSE] ) 
 | 
			
		||||
			.filter( k => k.getAttribute("visible") )
 | 
			
		||||
			.map( k => {
 | 
			
		||||
				// should only look at visible keys, could limit via .filter( k => k.getAttribute("visible") == "true")
 | 
			
		||||
					// this way one wouldn't type on an invisible keyboard
 | 
			
		||||
				let d1 = k.object3D.position.distanceTo( pos1 )
 | 
			
		||||
				let d2 = k.object3D.position.distanceTo( pos2 )
 | 
			
		||||
				let d3 = k.object3D.position.distanceTo( pos3 )
 | 
			
		||||
				let d4 = k.object3D.position.distanceTo( pos4 )
 | 
			
		||||
				if ( d1 < threshold || d2 < threshold || d3 < threshold || d4 < threshold) {
 | 
			
		||||
				//if ( d1 < threshold || d2 < threshold) {
 | 
			
		||||
					k.setAttribute("color", "pink")
 | 
			
		||||
					if (keyboardTarget == typinghud) typinghud.setAttribute("material","opacity", .5)
 | 
			
		||||
					if ( Date.now() - lastKeypress < refractionPeriod ){
 | 
			
		||||
						// console.warn('ignoring, executed during the last 500ms already')
 | 
			
		||||
						let x = 42 // added just to ignore
 | 
			
		||||
					} else {
 | 
			
		||||
						lastKeypress = Date.now()
 | 
			
		||||
						let value = k.firstChild.getAttribute("value")  
 | 
			
		||||
						if ( keyboardTarget.getAttribute("value") == "[]" ) keyboardTarget.setAttribute("value", "" ) // for typinghud starting value
 | 
			
		||||
						if (value == "TAB") console.warn('does not complete yet') // TODO add completion
 | 
			
		||||
						if (value == "SPC") value = " "
 | 
			
		||||
						if (value == "ENT") {
 | 
			
		||||
							if (keyboardTarget == typinghud) {
 | 
			
		||||
								parseKeys("keydown", "Enter")
 | 
			
		||||
								keyboardTarget.setAttribute("value", "" )
 | 
			
		||||
							} else {
 | 
			
		||||
								keyboardTarget.setAttribute("value", keyboardTarget.getAttribute("value") + '\n' )
 | 
			
		||||
							}
 | 
			
		||||
						} else if (value == "SHFT") {
 | 
			
		||||
							shiftFromVirtualKeyboard = !shiftFromVirtualKeyboard
 | 
			
		||||
							// visual highlight, also note that is closer to CAPSLOCK behavior
 | 
			
		||||
							keys_from_drumsticks_0_SHFT.setAttribute("wireframe", shiftFromVirtualKeyboard) // arguable, could do so for all layers
 | 
			
		||||
						} else if (value == "RSE") {
 | 
			
		||||
							if (layerFromVirtualKeyboard<2) layerFromVirtualKeyboard++ // hardcoded max
 | 
			
		||||
							console.log('should raise layer', layerFromVirtualKeyboard) // a la CAPSLOCK too
 | 
			
		||||
							Array.from( document.querySelectorAll(".keys_from_drumsticks") ).map( k => k.setAttribute("visible", "false") )
 | 
			
		||||
							Array.from( document.querySelectorAll(".keys_from_drumsticks"+".layer_"+layerFromVirtualKeyboard) ).map( k => k.setAttribute("visible", "true") )
 | 
			
		||||
							// forcing visibility yet get ignored as on wrong layer
 | 
			
		||||
							keys_from_drumsticks_0_LWR.setAttribute("visible", "true")
 | 
			
		||||
							keys_from_drumsticks_0_RSE.setAttribute("visible", "true")
 | 
			
		||||
						} else if (value == "LWR") {
 | 
			
		||||
							if (layerFromVirtualKeyboard>0) layerFromVirtualKeyboard--
 | 
			
		||||
							console.log('should lower layer', layerFromVirtualKeyboard) // a la CAPSLOCK too
 | 
			
		||||
							Array.from( document.querySelectorAll(".keys_from_drumsticks") ).map( k => k.setAttribute("visible", "false") )
 | 
			
		||||
							Array.from( document.querySelectorAll(".keys_from_drumsticks"+".layer_"+layerFromVirtualKeyboard) ).map( k => k.setAttribute("visible", "true") )
 | 
			
		||||
							keys_from_drumsticks_0_LWR.setAttribute("visible", "true")
 | 
			
		||||
							keys_from_drumsticks_0_RSE.setAttribute("visible", "true")
 | 
			
		||||
						} else if (value == "BKSP") {
 | 
			
		||||
							keyboardTarget.setAttribute("value", keyboardTarget.getAttribute("value").slice(0,-1) ) 
 | 
			
		||||
						} else {
 | 
			
		||||
							if (!shiftFromVirtualKeyboard) value = value.toLowerCase()
 | 
			
		||||
							keyboardTarget.setAttribute("value", keyboardTarget.getAttribute("value") + value )
 | 
			
		||||
						}
 | 
			
		||||
						keyboardEl.emit( "keypressed", {key: value} )
 | 
			
		||||
					}
 | 
			
		||||
				} else if ( d1 < threshold*1.2 || d2 < threshold*1.2) {  // arguably, not convinced it brings value more than confusion
 | 
			
		||||
					k.setAttribute("color", "#ffe4e1") 
 | 
			
		||||
				} else {
 | 
			
		||||
					k.setAttribute("color", "white")
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		}, 20)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return keyboardEl
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
 | 
			
		||||
							
								
								
									
										2
									
								
								drumkeyboard/root/scene-drumkeyboard/index.html
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								drumkeyboard/root/scene-drumkeyboard/index.html
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
#!/bin/html
 | 
			
		||||
<a-text value="drumkeyboard demo scene" position="-0.5 1.5 -2.5"></a-text>
 | 
			
		||||
							
								
								
									
										22
									
								
								drumkeyboard/root/scene-drumkeyboard/index.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								drumkeyboard/root/scene-drumkeyboard/index.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
AFRAME.registerComponent('bind-element-to-finger', {
 | 
			
		||||
  multiple: true,
 | 
			
		||||
  schema: {
 | 
			
		||||
	hand: {type: 'string', default: 'r_handMeshNode'},
 | 
			
		||||
	finger: {type: 'string', default: 'index-finger-tip'},
 | 
			
		||||
	target : {type: 'selector'},
 | 
			
		||||
  },
 | 
			
		||||
  tick: function (time, timeDelta) {
 | 
			
		||||
	const joint = AFRAME.scenes[0].object3D.getObjectByName(this.data.hand)?.parent.getObjectByName(this.data.finger)
 | 
			
		||||
	if ( joint && this.data.target.object3D.parent == AFRAME.scenes[0].object3D ) this.data.target.object3D.parent = joint
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
window.keyboardTarget = typinghud
 | 
			
		||||
let kbd = addDrumKeyboard()
 | 
			
		||||
kbd.addEventListener( "keypressed", e => {
 | 
			
		||||
  document.querySelector("[isoterminal]").components.isoterminal.term.send(e.detail.key)
 | 
			
		||||
  // consider executing the content on ENTER
 | 
			
		||||
    // document.querySelector("[isoterminal]").components.isoterminal.term.exec("ls")
 | 
			
		||||
    // raw keypress, this getting SHFT, ENT, etc
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue