keyTyped() not responding in p5.js editor

I have some code in the p5.js editor that is not responding to keyTyped() or keyPressed() events. A slider interface element is also not responding. Possibly it’s an issue with the browser, but other interface elements do respond, and the focus seems to be on the canvas and its frame. Here’s the URL: SignalToImage.

A short test example works without a problem: keyTyped test.

Here’s the code:

// keyTyped function is not responding
// slider (created in initUI function) is also not responding
// they work in other, simpler, examples: https://editor.p5js.org/Ignotus_Mago/sketches/CvGN07-Hr

var img = [];          // array of color values in bitmap row major order
var sig = [];          // array of color values in Hilbert curve order
var hilbDepth = 5;     // maximum value of 6, to draw curve clearly
var hilbCount;         // number of rows or columns in the grid
// for hilbDepth of 2, sigLUT should be [0,1,5,4,8,12,13,9,10,14,15,11,7,6,2,3]
var sigLUT = [];       // look up table for index numbers into the img array
var imgLUT = [];       // look up table for index numbers into the sig array
var w = 512;
var h = 512;
var loadSignal = true;
var showPath = false;
var bitmapBtn;
var hilbertBtn;
var canv;


function setup() {
  canv = createCanvas(w, h);
  frameRate(30);
  var hilb = new HilbGen(hilbDepth);
  hilbCount = hilb.d;                // number of rows or columns in the grid
  if (hilbCount > w/16) console.log("hilbDepth should not exceed 6.");
  imgLUT = hilb.indexMap;       
  for (let i = 0; i < imgLUT.length; i++) {
    sigLUT[imgLUT[i]] = i;      
  }
  console.log("sigLUT: ", sigLUT);   
  console.log("imgLUT: ", imgLUT);   
  console.log("hilb.indexMap: ", hilb.indexMap);
  gridW = w/hilbCount;               // width of grid elements
  gridH = h/hilbCount;               // height of grid elements
  gridHalf = gridW/2;                // half the width of an element
  initSignal();
  initUI();
}

function draw() {
  if (frameCount % 30 == 1) rotateData();
  if (showPath) drawSignalPath();
}

function initSignal() {
  let steps = sigLUT.length;
  let ang = 45;
  let inc = 360/steps;
  colorMode(HSL, 360, 100, 100);
  if (loadSignal) {
    for (let i = 0; i < sigLUT.length; i++) {
      let c = color((ang + round(i * inc)) % 360, 60, 50);  // generate color spectrum
      sig[i] = c;                                           // assign current color to sig
      img[sigLUT[i]] = c;                                   // map the same color to img
    }
  }
  else {
    for (let i = 0; i < sigLUT.length; i++) {
      let c = color((ang + round(i * inc)) % 360, 60, 50);  // generate color spectrum
      img[i] = c;                                           // assign current color to img
      sig[imgLUT[i]] = c;                                   // map the same color to sig
      // console.log("image index", imgLUT[i], hue(c));
    }    
  }
  fillSquares();
}

function initUI() {
  let txt1 = createDiv('Click on the canvas to flip a color.');
  txt1.position(12, 524);
  let txt2 = createDiv('Animate: ');
  txt2.position(12, 548);
  hilbertBtn = createButton("Hilbert");
  hilbertBtn.id('hilbert');
  hilbertBtn.position(80, 548);
  hilbertBtn.mousePressed(animateHilbert);
  if (loadSignal) hilbertBtn.hide();
  bitmapBtn = createButton("Bitmap");
  bitmapBtn.id('bitmap');
  bitmapBtn.position(80, 548);
  bitmapBtn.mousePressed(animateBitmap);
  if (!loadSignal) bitmapBtn.hide();
  let resetBtn = createButton("Reset");
  resetBtn.id('reset');
  resetBtn.mousePressed(() => {
    loadSignal = true; initSignal(); bitmapBtn.show(); hilbertBtn.hide()});
  resetBtn.position(12, 572);
  let pathCheckbox = createCheckbox(" Draw Path", showPath);
  pathCheckbox.id('path');
  let xPos = 12 + resetBtn.width + 32;
  pathCheckbox.position(xPos, 572);
  pathCheckbox.mouseReleased(() => {showPath = !showPath;});
  let txt3 = createDiv("FPS");
  txt3.id('fps');
  xPos += 200;
  txt3.position(xPos, 572);
  // SLIDER is not working
  let animSlider = createSlider(1, 120, 10);
  animSlider.id('anim');
  animSlider.size(120);
  xPos += 40;
  animSlider.position(xPos, 572);
  
}

function rotateData() {
  // to rotate array the other direction: sig.push(sig.shift());
  if (loadSignal) {
    sig.unshift(sig.pop());    // rotate sig array
    mapSigToImg();
  }
  else {
    img.unshift(img.pop());    // rotate img array
    mapImgToSig();
  }
  push();
  fillSquares();
  pop();
}

function drawSignalPath() {
  push();
  stroke(255);
  noFill();
  strokeWeight(1);
  beginShape();
  for (let i = 0; i < sigLUT.length; i++) {
    let p = sigLUT[i];
    let x = p % hilbCount * gridW + gridHalf;
    let y = floor(p/hilbCount) * gridH + gridHalf;
    vertex(x,y);
  }
  endShape();  
  pop();
}

function fillSquares() {
  for (let i = 0; i < sigLUT.length; i++) {
    // get the index number stored at sigLUT[i]
    let p = sigLUT[i];
    // convert the index to coordinates
    let x = p % hilbCount * gridW;
    let y = floor(p/hilbCount) * gridH;
    // get the color value from sig[i]
    fill(sig[i]);
    noStroke();
    square(x, y, gridW);
  }
}

function mousePressed() {
  if (pointInCanvas(mouseX, mouseY)) {
    // get x and y coordinates, scale to the grid
    let x = floor(mouseX/gridW);
    let y = floor(mouseY/gridH);
    // console.log(mouseX, mouseY, x, y);
    // convert the coordinates into index value p for imgLUT
    let p = x + y * hilbCount;
    // retrieve the index value i for sigLUT from imgLUT
    let i = imgLUT[p];
    // get the color from sig[i]
    let c = sig[i];
    // console.log("----->>> p = "+ p +", i = "+ i +", c = "+ c);
    colorMode(HSL, 360, 100, 100);
    let h = Math.floor(hue(c));
    console.log("--->> new hue:", h);
    c = color((h + 180) % 360, 90, 80);
    sig[i] = c;
    img[sigLUT[i]] = c;
    fillSquares();
  }
  return false;
}

// NOT responding
function keyTyped() {
  console.log("--->> key "+ key);
  return false;
}

function pointInCanvas(x, y) {
  return (x >= 0 && x <= width && y >= 0  && y <= height);
}

function animateHilbert() {
  if (!loadSignal) writeImgToSig();
  loadSignal = true;
  bitmapBtn.show();
  hilbertBtn.hide();
}

function animateBitmap() {
  if (loadSignal) writeSigToImg();
  loadSignal = false;
  hilbertBtn.show();
  bitmapBtn.hide();
}

function mapImgToSig() {
  for (let i = 0; i < img.length; i++) {
    sig[imgLUT[i]] = img[i];
  }
}

function mapSigToImg() {
  for (let i = 0; i < sig.length; i++) {
    img[sigLUT[i]] = sig[i];
  }
}

function writeImgToSig() {
  for (let i = 0; i < img.length; i++) {
    sig[i] = img[i];
  }
}

function writeSigToImg() {
  for (let i = 0; i < sig.length; i++) {
    img[i] = sig[i];
  }
}


// LUT generator class creates the lookup table for Hilbert curve
class HilbGen {
  constructor(depth) {
    this.depth = depth;
    this.d = round(pow(2, depth));
    this.n = this.d * this.d;
    console.log("--->> HilbGen: ", this.depth, this.d, this.n);
    this.bertX = 0;
    this.bertY = 0;
    this.indexMap = [this.n];
    this.doXYSwap = (depth % 2 == 1);
    this.generateMap();
  }
  
  generateMap() {
    let index = 0;
    for (let i = 0; i < this.n; i++) {
      this.d2xy(this.n, i);
      index = this.bertX + this.d * this.bertY;
      // console.log(i, "index "+ index +", bertX "+ this.bertX +", bertY "+ this.bertY);
      this.indexMap[index] = i;
    }
  }
  
  d2xy(pts, pos) {
    let rx = 0;
    let ry = 0;
    let t = pos;
    let s = 0;
    this.bertX = 0;
    this.bertY = 0;
    for (let s = 1; s < pts; s *= 2) {
      rx = 1 & (floor(t/2));
      ry = 1 & (floor(t ^ rx));
      this.rot(s, rx, ry);
      this.bertX += s * rx;
      this.bertY += s * ry;
      t = floor(t/4);
    }
    if (this.doXYSwap) {
      this.swapXY();
    }
  }

  swapXY() {
    let temp = this.bertY;
    this.bertY = this.bertX
    this.bertX = temp;
  }
  
  rot(s, rx, ry) {
    if (ry == 0) {
      if (rx == 1) {
        this.bertX = s - 1 - this.bertX;
        this.bertY = s - 1 - this.bertY;
      }
      // swap bertX and bertY
      this.swapXY()
    }
  }
  

}

And the short example:

var canv;

function setup() {
  canv = createCanvas(400, 400);
  makeSlider();
}

function draw() {
  background(220);
}

function keyTyped() {
  console.log("keyTyped function: key", key);
}

function makeSlider() {
  let animSlider = createSlider(1, 120, 10);
  animSlider.id('anim');
  animSlider.size(120);
  animSlider.position(12, 428);
}

I’ve tried such strategies as HTMLElement.focus(animSlider), for the slider, only to throw an error. Focus may not be the problem, anyhow. Commenting out my drawing code also failed to let me detect key presses – this is really odd, but seems to mean that the animation is probably not blocking events.

Any hints on how to proceed are most welcome. If I can solve it in the p5.js Editor, that would be great. It makes it easy to share code. But perhaps the editor is part of the problem – though other code to detect key presses seems to run just fine.

ciao,

Paul

I have “solved” the keyTyped issue, but not the slider. I solved the key input whilst mucking about with the HTML for the slider. Here’s the code, sort of a workaround.

  // SLIDER is still not working, but focus and blur calls enable keyTyped() 
  let animSlider = createSlider(1, 120, 10);
  animSlider.id('anim');
  animSlider.size(120);
  xPos += 40;
  animSlider.position(xPos, 572); 
  anim.focus();
  anim.blur();

Problems with keyboard input can often be solved by clicking in the sketch to make sure that the HTML iframe that contains it has focus. Clicking in the canvas or in its frame did not work for me. However, it seems that giving focus to an element within the frame enables focus for the frame.

1 Like

A little more information:

Clicking on the the checkbox twice also enables keyTyped(), without calling focus() and blur() on the slider. It did not improve the response of the slider. Adding focus() and blur() on the slider has no effect. The slider doesn’t respond.

Isolating the code in its own page in a Visual Studio Code and running it in Chrome immediately allowed capture of key strokes with keyTyped(). It did not improve the response of the slider.

2 Likes

This is only a partial solution. The slider remains non-functional, and I don’t really know why. The rest of the code is doing what I want, so I’ll put the matter to rest. Next time I use a slider in the p5js editor, I will build the UI step-by-step to see it the problem recurs and how it happens (or doesn’t).

2 Likes