1

I want some code for a task that requires users to memorise a number. The task should work as follows:

The user is directed to press down a combination of three keys in order to display the number they need to remember. These can be any three keys as long as it will require the user to use both hands (the idea being that this will prevent them from writing down the number they are supposed to be memorising).

When they begin to hold down the keys, the number is displayed and a timer starts. If they keep holding down the keys for the requisite period of time (15 seconds), a function runs automatically (this is another task they have to do while remembering the number).

However, if they release the keys before the 15 seconds is up, a different function runs. This function just informs them that they released the keys too early, and when they click on a button the task restarts with a new number.

The code I currently have looks like this:

var mapDown = {}; // Global object to store keydown events
var mapUp = {}; // Global object to store keyup events

This function generates the random number to be memorised using the function numberFunc() (not shown) and runs the page.

function keyDownFunc() {
  mapDown = {};
  mapUp = {};
  memoryNum = numberFunc(); 
  $('#experimentDisplay').load('./html/numberTest.html');
  $('#experimentDisplay').show();
}

The function below is in the script for the page called above. It displays the number to be memorised in a div called 'numberTestDiv'. At present (for simplicity), it is set up to run when the 'p' and 'q' keys are held down.

<script>
onkeydown = onkeyup = function(e){
    e = e || event; // to deal with IE
    mapDown[e.keyCode] = e.type == 'keydown';
    mapUp[e.keyCode] = e.type == 'keyup';

    if(mapDown[80] && mapDown[81]) {
       $("#numberTestDiv").html(memoryNum);
       timer = setTimeout(runTrial, 15000);
     }; // run the function runTrial() if the keys are held down for the requisite period

     if (mapUp[80] || mapUp[81]) {
       mapDown = {};
       clearTimeout(timer);
       keyUpFunc(); // stop the timer and run the function keyUpFunc() if either of the keys are released too early
     }

}
</script>

If the user releases the keys too early, the function keyUpFunc is called. This clears the mapDown and mapUp objects and the timer, and takes the user to a page where they can click to start the process again.

function keyUpFunc() {
  mapDown = {};
  mapUp = {};
  clearTimeout(timer);
  $('#experimentDisplay').load('./html/keyUp.html');
  $('#experimentDisplay').show();
}

There are a couple of problems with the above.

1) If the user holds down the keys and proceeds to the main task, the screen flickers for quite some time - I assume because of all the events the extended key holds have generated. I cannot work out how to avoid this. I have read that modifier keys auto-repeat

2) The clearTimeout() function does not seem to be working. If the user releases the keys early, is directed to the keyUpFunc function, and then launches the keyDownFunc function again, they do not have to hold down the 'p' and 'q' keys for 15 seconds (or at all) to proceed to the runTrial function.

Other answers consulted include: JavaScript multiple keys pressed at once Get a list of all currently pressed keys in Javascript Run code after some time has passed or a condition is met

userLL
  • 471
  • 5
  • 15

1 Answers1

1

Adding in a flag that stores whether the code for holding both buttons down is already running and then using that as a condition for running the code should solve your problems. This basically just stops the code from running hundreds of times when you are holding the button down or lift a button up. Here is some example code:

var going = 0;
onkeydown = onkeyup = function(e){    
 e = e || event; // to deal with IE
 mapDown[e.keyCode] = e.type == 'keydown';
 mapUp[e.keyCode] = e.type == 'keyup';
  if(going==0){
    if(mapDown[80] && mapDown[81]) {
       going = 1;
       timer = setTimeout(runTrial, 15000);
     }; // run the function runTrial() if the keys are held down for the requisite period
  } else if(going==1){
     if (mapUp[80] || mapUp[81]) {
      going = 0;
      clearTimeout(timer);
      keyUpFunc(); // stop the timer and run the function keyUpFunc() if either of the keys are released too early
     }
  }
}

runTrial = function(){
 going = 0; //This just resets the going value for the next trial. It may not be necessary if you just store going as a local variable and reset it at the start each time. 
 console.log("all done"); // replace this with the correct function.
}
Cam
  • 158
  • 1
  • 9