diff --git a/plugins/jspsych-video-keyboard-response.js b/plugins/jspsych-video-keyboard-response.js new file mode 100644 index 00000000..a2233973 --- /dev/null +++ b/plugins/jspsych-video-keyboard-response.js @@ -0,0 +1,190 @@ +/** + * jspsych-video-keyboard-response + * Josh de Leeuw + * + * plugin for playing a video file and getting a keyboard response + * + * documentation: docs.jspsych.org + * + **/ + +jsPsych.plugins["video-keyboard-response"] = (function() { + + var plugin = {}; + + jsPsych.pluginAPI.registerPreload('video-keyboard-response', 'stimulus', 'video'); + + plugin.info = { + name: 'video-keyboard-response', + description: '', + parameters: { + stimulus: { + type: jsPsych.plugins.parameterType.VIDEO, + pretty_name: 'Stimulus', + default: undefined, + description: 'The video file to play.' + }, + choices: { + type: jsPsych.plugins.parameterType.KEYCODE, + pretty_name: 'Choices', + array: true, + default: jsPsych.ALL_KEYS, + description: 'The keys the subject is allowed to press to respond to the stimulus.' + }, + prompt: { + type: jsPsych.plugins.parameterType.STRING, + pretty_name: 'Prompt', + default: null, + description: 'Any content here will be displayed below the stimulus.' + }, + width: { + type: jsPsych.plugins.parameterType.INT, + pretty_name: 'Width', + default: '', + description: 'The width of the video in pixels.' + }, + height: { + type: jsPsych.plugins.parameterType.INT, + pretty_name: 'Height', + default: '', + description: 'The height of the video display in pixels.' + }, + autoplay: { + type: jsPsych.plugins.parameterType.BOOL, + pretty_name: 'Autoplay', + default: true, + description: 'If true, the video will begin playing as soon as it has loaded.' + }, + controls: { + type: jsPsych.plugins.parameterType.BOOL, + pretty_name: 'Controls', + default: false, + description: 'If true, the subject will be able to pause the video or move the playback to any point in the video.' + }, + trial_duration: { + type: jsPsych.plugins.parameterType.INT, + pretty_name: 'Trial duration', + default: null, + description: 'How long to show trial before it ends.' + }, + response_ends_trial: { + type: jsPsych.plugins.parameterType.BOOL, + pretty_name: 'Response ends trial', + default: true, + description: 'If true, the trial will end when subject makes a response.' + } + } + } + + plugin.trial = function(display_element, trial) { + + // setup stimulus + var video_html = '"; + + // add prompt if there is one + if (trial.prompt !== null) { + video_html += trial.prompt; + } + + display_element.innerHTML = video_html; + + if(video_preload_blob){ + display_element.querySelector('#jspsych-video-keyboard-response-stimulus').src = video_preload_blob; + } + + // store response + var response = { + rt: null, + key: null + }; + + // function to end trial when it is time + function end_trial() { + + // kill any remaining setTimeout handlers + jsPsych.pluginAPI.clearAllTimeouts(); + + // kill keyboard listeners + jsPsych.pluginAPI.cancelAllKeyboardResponses(); + + // gather the data to store for the trial + if(response.rt !== null){ + response.rt = Math.round(response.rt * 1000); + } + var trial_data = { + "rt": response.rt, + "stimulus": trial.stimulus, + "key_press": response.key + }; + + // clear the display + display_element.innerHTML = ''; + + // move on to the next trial + jsPsych.finishTrial(trial_data); + }; + + // function to handle responses by the subject + var after_response = function(info) { + + // after a valid response, the stimulus will have the CSS class 'responded' + // which can be used to provide visual feedback that a response was recorded + display_element.querySelector('#jspsych-video-keyboard-response-stimulus').className += ' responded'; + + // only record the first response + if (response.key == null) { + response = info; + } + + if (trial.response_ends_trial) { + end_trial(); + } + }; + + // start the response listener + if (trial.choices != jsPsych.NO_KEYS) { + var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({ + callback_function: after_response, + valid_responses: trial.choices, + rt_method: 'performance', + persist: false, + allow_held_key: false, + }); + } + + // end trial if time limit is set + if (trial.trial_duration !== null) { + jsPsych.pluginAPI.setTimeout(function() { + end_trial(); + }, trial.trial_duration); + } + }; + + return plugin; +})();