From 3b7ce6daab5a9c860643b86887ec92e881b41a91 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Tue, 29 Jul 2025 10:59:32 +0200 Subject: [PATCH] 1st commit fabien's drumkeyboard --- README.md | 1 + drumkeyboard/.env | 18 ++ drumkeyboard/README.md | 5 + drumkeyboard/build.sh | 4 + drumkeyboard/package.drumkeyboard.zip | Bin 0 -> 5906 bytes drumkeyboard/root/scene-drumkeyboard/.env | 4 + .../root/scene-drumkeyboard/.env.leave | 1 + .../root/scene-drumkeyboard/drumkbd.js | 229 ++++++++++++++++++ .../fabien_corneish_zen.keymap | 1 + .../root/scene-drumkeyboard/index.html | 2 + drumkeyboard/root/scene-drumkeyboard/index.js | 22 ++ 11 files changed, 287 insertions(+) create mode 100755 drumkeyboard/.env create mode 100644 drumkeyboard/README.md create mode 100755 drumkeyboard/build.sh create mode 100644 drumkeyboard/package.drumkeyboard.zip create mode 100755 drumkeyboard/root/scene-drumkeyboard/.env create mode 100644 drumkeyboard/root/scene-drumkeyboard/.env.leave create mode 100644 drumkeyboard/root/scene-drumkeyboard/drumkbd.js create mode 100644 drumkeyboard/root/scene-drumkeyboard/fabien_corneish_zen.keymap create mode 100755 drumkeyboard/root/scene-drumkeyboard/index.html create mode 100644 drumkeyboard/root/scene-drumkeyboard/index.js diff --git a/README.md b/README.md index 9035af7..9c436af 100644 --- a/README.md +++ b/README.md @@ -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 | diff --git a/drumkeyboard/.env b/drumkeyboard/.env new file mode 100755 index 0000000..93fa739 --- /dev/null +++ b/drumkeyboard/.env @@ -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 + diff --git a/drumkeyboard/README.md b/drumkeyboard/README.md new file mode 100644 index 0000000..2e2e5bb --- /dev/null +++ b/drumkeyboard/README.md @@ -0,0 +1,5 @@ +# Drumkeyboard + +A customizable keyboard component + +> NOTE: after importing package run `cd ~/scene-drumkeyboard` to load the demoscene diff --git a/drumkeyboard/build.sh b/drumkeyboard/build.sh new file mode 100755 index 0000000..1539bf6 --- /dev/null +++ b/drumkeyboard/build.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -e +name=drumkeyboard +zip -r package.$name.zip root .env .env.leave diff --git a/drumkeyboard/package.drumkeyboard.zip b/drumkeyboard/package.drumkeyboard.zip new file mode 100644 index 0000000000000000000000000000000000000000..987ddd1b71711c64859a905669e97d8577b01f93 GIT binary patch literal 5906 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 PQry!C2L /root/index.js diff --git a/drumkeyboard/root/scene-drumkeyboard/.env.leave b/drumkeyboard/root/scene-drumkeyboard/.env.leave new file mode 100644 index 0000000..a9f4150 --- /dev/null +++ b/drumkeyboard/root/scene-drumkeyboard/.env.leave @@ -0,0 +1 @@ +echo "" > /root/index.html # cleanup diff --git a/drumkeyboard/root/scene-drumkeyboard/drumkbd.js b/drumkeyboard/root/scene-drumkeyboard/drumkbd.js new file mode 100644 index 0000000..ed3b56f --- /dev/null +++ b/drumkeyboard/root/scene-drumkeyboard/drumkbd.js @@ -0,0 +1,229 @@ +// let sequentialFilters = [] +// + +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 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 +} diff --git a/drumkeyboard/root/scene-drumkeyboard/fabien_corneish_zen.keymap b/drumkeyboard/root/scene-drumkeyboard/fabien_corneish_zen.keymap new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/drumkeyboard/root/scene-drumkeyboard/fabien_corneish_zen.keymap @@ -0,0 +1 @@ + diff --git a/drumkeyboard/root/scene-drumkeyboard/index.html b/drumkeyboard/root/scene-drumkeyboard/index.html new file mode 100755 index 0000000..5d3c393 --- /dev/null +++ b/drumkeyboard/root/scene-drumkeyboard/index.html @@ -0,0 +1,2 @@ +#!/bin/html + diff --git a/drumkeyboard/root/scene-drumkeyboard/index.js b/drumkeyboard/root/scene-drumkeyboard/index.js new file mode 100644 index 0000000..8f29233 --- /dev/null +++ b/drumkeyboard/root/scene-drumkeyboard/index.js @@ -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 +}) +