Recording Typed Responses #772
-
Hi! I have learned HTML/JS/JsPsych all to make an online experiment that I need to for my dissertations, so its been a very steep curve and a stressful time. I've been absolutely struggling trying to make a keylogging structure so that I can record the typed responses from the survey-text type trials. I have a plugin that should kind of work but I'm having trouble figuring out how to incorporate it into my experiment code. Any help would be appreciated! This is the keylogging plugin that I should be able to make work: function toPx(str) {
// convert string to pixels
return (str).toString()+"px";
}
function displayText(parentId, textDivId, text, size, top) {
// append text (centred) in div to parent container
var div = document.createElement("div");
div.id = textDivId;
div.style.position = "absolute";
div.style.top = toPx(top); // 10% from parent top
div.style.left = toPx(w/10); // 10% from parent left
div.style.width = "80%";
div.style.backgroundColor = "#ffffff";
div.style.textAlign = "center";
div.style.fontSize = toPx(size);
div.style.fontFamily = "Arial";
div.innerHTML = text;
document.getElementById(parentId).appendChild(div);
}
function checkRemoveElem(elemId, parentId) {
// check if parentId contains child element and remove if so
if (document.getElementById(parentId).contains(document.getElementById(elemId))) {
document.getElementById(elemId).remove();
}
}
//this is the main div
var div = document.createElement("div");
div.id = "mainDiv";
div.style.position = "absolute";
div.style.backgroundColor = "none";
div.style.top = "0px";
div.style.left = "0px";
div.style.height = "100%";
div.style.width = "100%";
document.body.appendChild(div);
// get div width and height
var w = document.getElementById('mainDiv').clientWidth;
var h = document.getElementById('mainDiv').clientHeight;
// viewport centre coords
var xc = w/2, yc = h/2;
// response textarea
var textarea = document.createElement("TEXTAREA");
textarea.id = "respBox";
textarea.style.width = "300px";
textarea.style.height = "100px";
textarea.style.position = "absolute";
textarea.style.left = toPx(xc-150);
textarea.style.top = "70px";
document.getElementById("mainDiv").appendChild(textarea);
// submit button
var button = document.createElement("button");
button.id = "submitButton";
button.style.position = "absolute";
button.style.width = "100px";
button.style.left = toPx(xc-50);
button.style.top = "300px";
button.innerHTML = "submit";
document.getElementById("mainDiv").appendChild(button);
function onSubmit() {
var typed = [], keycodes = [];
function keyListener(e) {
var code = e.keyCode || e.which,
str = String.fromCharCode(code);
typed.push(str);
keycodes.push(code);
}
// check for keydown event
document.getElementById("respBox").addEventListener("keydown", keyListener);
// check for click event on submit button
document.getElementById("submitButton").addEventListener("click", function () {
checkRemoveElem("textDiv", "mainDiv"); // clear text from previous submit
displayText("mainDiv", "textDiv", typed, 20, 500); // blit current submit
console.log(typed);
console.log(keycodes);
typed.length = 0; // reset array
keycodes.length = 0;
}, false);
}
var inst = "Type and press submit";
displayText("mainDiv", "instDiv", inst, 24, 30);
displayText("mainDiv", "instDiv2", "Keys pressed:", 24, 450);
onSubmit(); And this is my experiment: <!DOCTYPE html>
<html>
<head>
<title>Typing Twisters</title>
<script src="js/jsPsych-6.1.0/jspsych.js"></script>
<script src="js/jsPsych-6.1.0/plugins/jspsych-html-button-response.js"></script>
<script src="js/jsPsych-6.1.0/plugins/jspsych-instructions.js" ></script>
<script src="js/jsPsych-6.1.0/plugins/jspsych-survey-likert.js"></script>
<script src="js/jsPsych-6.1.0/plugins/jspsych-survey-text.js"></script>
<script src="js/jsPsych-6.1.0/plugins/jspsych-keylogger.js"></script>
<script src="js/jsPsych-6.1.0/plugins/jspsych-survey-multi-select.js"></script>
<script src="js/utilities.js"></script>
<link href="css/jspsych.css" rel="stylesheet" type="text/css">
</head>
<body>
<div id="jspsych-target"></div>
</body>
<script>
//welcome
var welcome_block = {
type: "html-button-response",
stimulus:"<p>Welcome to this experiment</p>",
choices:['continue']
};
//Instructions
var instruction_block1 = {
data: {
screen_id: "instructions"
},
type: "instructions",
pages: [
"<p>Please answer the following demographic questions.</p>",
],
show_clickable_nav: true
};
//survey
// generate a random subject ID with 15 characters
var subject_id = jsPsych.randomization.randomID(15);
// pick a random condition for the subject at the start of the experiment
var condition_assignment = jsPsych.randomization.sampleWithoutReplacement(['conditionA', 'conditionB', 'conditionC', 'conditionD'], 1)[0];
// record the condition assignment in the jsPsych data
// this adds a property called 'subject' and a property called 'condition' to every trial
jsPsych.data.addProperties({
subject: subject_id,
condition: condition_assignment
});
var survey_page1 = {
type: 'survey-text',
questions: [
{prompt:'Create an original ID for anonymity', placeholder: 'ID', columns: 50, name: 'IDA'},
{prompt: 'How old are you?', columns: 3, required: true, name: 'Age'},
{prompt: 'What country are you from/a citizen of?', placeholder: 'Country', columns: 50, name: 'BirthLocation'}
]
};
var multi_select_block = {
type: 'survey-multi-select',
preamble:"<b>Please answer to the best of your ability.</b>",
questions: [
{prompt: "Are you right-handed, left-handed or ambidexturous?",
options: ["Right-handed", "Left-handed", "ambidexturous"],
horizontal: true,
required: true,
name: 'hand'
}],
data:"hand type"
};
//Practice instructions
var instruction_block2 = {
data: {
screen_id: "instruction2"
},
type: "instructions",
pages: [
"<p>Please type the sequence of words that you see to the best of your ability.</p>"+
"<p>The practice trials are not timed so please press any key to move on to the next page.</p>",
],
show_clickable_nav: true
};
//Practice
var practice_trial1 = {
type: 'survey-text',
questions: [
{prompt:'five tide type fine'}
],
choices: "ALL_KEYS",
trial_duration: null,
};
var practice_trial2 = {
type: 'survey-text',
questions: [
{prompt: 'five tide tap mine'}
],
choices: "ALL_KEYS",
trial_duration: null,
};
//Experiment instructions
var instruction_block3 = {
data: {
screen_id: "instruction3"
},
type: "instructions",
pages: [
"<p>Please type the sequence of words that you see to the best of your ability.</p>"+
"<p>You will only have a limited amount of time to type each sequence</p>",
],
show_clickable_nav: true
};
//Experimental trials
var survey_trial1= {
type: 'survey-text',
questions: [
{prompt: "cow bill bat cap"},
],
choices: "ALL_KEYS",
trial_duration: 2000,
data:"trial1",
};
var survey_trial2= {
type: 'survey-text',
questions: [
{prompt: 'rib mess mad rag'}
],
choices: "ALL_KEYS",
trial_duration: 2000,
data:"trial2",
};
//Typing Survey Questions
var scale = ["Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"];
var likert_trial = {
type: 'survey-likert',
questions: [
{prompt: "I typically make many mistakes when typing", name: 'TypicalTyping', labels: scale, required: true},
{prompt: "Today I made more typing mistakes than usual.", name: 'TodayTyping', labels: scale, required: true}
],
data:"typing confidence"
};
//Debrief
var debrief = {
type: "html-button-response",
stimulus:"<h1>Thank you for participating!</h1>",
choices: ["Click any key to exit the experiment."]
};
//timeline
var timeline= []
timeline.push(welcome_block),
timeline.push(instruction_block1),
timeline.push(survey_page1),
timeline.push(multi_select_block)
timeline.push(instruction_block2),
timeline.push(practice_trial1),
timeline.push(practice_trial2),
timeline.push(instruction_block3),
timeline.push(survey_trial1),
timeline.push(survey_trial2),
timeline.push(likert_trial);
timeline.push(debrief);
jsPsych.init ({
timeline: timeline,
show_progress_bar: true,
display_element: 'jspsych-target',
on_finish: function() {
var csv = jsPsych.data.get().csv();
var filename = "TT.csv";
var div = jsPsych.data.get().filter({trial_type: 'survey-text'});
var textarea = "TEXTAREA";
var button = "button";
var inst = "Type and press submit";
downloadCSV(csv, filename);
jsPsych.data.displayData('csv')
}
});
</script>
</html> |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
Hi @rabrya0072! Quick clarifying question: Is your goal to capture all of the key presses that someone makes while typing in a text field, including things like backspace to delete and make changes? |
Beta Was this translation helpful? Give feedback.
-
I think one way to do this would be to adapt the This isn't a full solution, but it sketches out the main idea: // store an array of the history of changes of the input element
var input_history = [];
// add event listener to input element, triggered on the input event.
document.querySelector('input').addEventListener('input', function(e){
// get the value of the input text field
var updated_value = e.target.value;
// add this value to history array
input_history.push(updated_value);
}); And at the end of the trial you could add the JSON version of this |
Beta Was this translation helpful? Give feedback.
-
Hi @rabrya0072 - This is exactly what I'm trying to do, and also having trouble. Your solution looks really good though. Is there any chance you could push your full code to a repo, or email me at [email protected]? Thanks, |
Beta Was this translation helpful? Give feedback.
I think one way to do this would be to adapt the
survey-text
plugin and use the input event to register the value of the text field every time it changes.This isn't a full solution, but it sketches out the main idea:
And at the end of the trial you could add the JSON version of this
input_history
to the trial…