Skip to content

Commit 3a6e4c0

Browse files
committed
define tests demos and errors for getResponse
1 parent 2132ca7 commit 3a6e4c0

File tree

4 files changed

+163
-48
lines changed

4 files changed

+163
-48
lines changed

demos/CPP_getResponseDemo.m

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,100 @@
11
%% Demo showing how to use the getResponse function
22

33
% This small script shows how to use the getReponse function
4-
% (a wrapper around the KbQueue function from PTB)
54

6-
% start with a clean slate
7-
cd ..
8-
clear; clc;
5+
% add parent directory to matlab path (so we can access the CPP_PTB functions)
6+
addpath(fullfile(pwd, '..'))
7+
8+
9+
%% start with a clean slate
10+
clear;
11+
clc;
12+
913
if IsOctave
1014
more off % for a better display experience
1115
end
1216

13-
%% set parameters
17+
% use the default set up (use main keyboard and use the ESCAPE key to abort)
18+
cfg = setDefaultsPTB;
1419

15-
% cfg.responseBox would be the device number of the device used by the participant to give his/her
16-
% response: like the button box in the scanner or a separate keyboard for a behavioral experiment
17-
%
18-
% cfg.keyboard would be the device number of the keyboard on which the experimenter will type or
19-
% press the keys necessary to start or abort the experiment.
20+
% show the default option
21+
disp(cfg.keyboard)
2022

21-
% cfg.responseBox and cfg.keyboard can be different or the same.
23+
%% set parameters
2224

23-
% If you want to know the device number of all the keyboards and responses
24-
% boxes connected to the computer you can use the following code.
25-
% [cfg.keyboardNumbers, cfg.keyboardNames] = GetKeyboardIndices
25+
% Change the values set by defaults (for more info about the keyboard see the doc)
26+
% cfg.keyboard.keyboard = ??
27+
% cfg.keyboard.responseBox = ??
28+
% cfg.keyboard.escapeKey = ??
2629

27-
% Using empty vectors should work for linux when to select the "main"
28-
% keyboard. You might have to try some other values for Windows. To
29-
% assigne a specific keyboard input the kb assigned value (see README)
30-
cfg.keyboard = [];
31-
cfg.responseBox = [];
30+
% Decide which device you want to collect responses from
31+
deviceNumber = []; % default device (PTB will find it for you)
32+
% deviceNumber = cfg.keyboard.keyboard; % the one you may have chosen as the main keyboard
33+
% deviceNumber = cfg.keyboard.responseBox; % the one you may have chosen as the response box
3234

33-
cfg.escapeKey = 'ESCAPE';
35+
% if you want getResponse to ignore the key release
36+
getOnlyPress = 1;
3437

3538
% We set which keys are "valid", any keys other than those will be ignored
36-
expParameters.responseKey = {};
39+
cfg.keyboard.responseKey = {'a', 'b'};
3740

41+
% This would make sure that you listen to presses of the escape key
42+
cfg.keyboard.responseKey{end+1} = cfg.keyboard.escapeKey;
3843

39-
%% init
4044

41-
% Keyboard
42-
% Make sure keyboard mapping is the same on all supported operating systems
43-
% Apple MacOS/X, MS-Windows and GNU/Linux:
44-
KbName('UnifyKeyNames');
45-
46-
47-
% we ask PTB to tell us which keyboard devices are connected to the computer
48-
[cfg.keyboardNumbers, cfg.keyboardNames] = GetKeyboardIndices;
49-
50-
cfg.keyboardNumbers
51-
cfg.keyboardNames
45+
%% Final checks
5246

47+
% Make sure keyboard mapping is the same on all supported operating systems
48+
KbName('UnifyKeyNames');
5349

5450
% Test that the keyboards are correctly configured
5551
testKeyboards(cfg);
5652

57-
% Give the time to the test key to be released and not listened
53+
% Give the time to the test key to be released and not listened to
5854
WaitSecs(1);
5955

60-
6156
fprintf('\nDuring the next 5 seconds we will collect responses on the following keys: \n\n');
62-
if isempty(expParameters.responseKey)
57+
if isempty(cfg.keyboard.responseKey)
6358
fprintf('\nALL KEYS\n\n');
6459
else
65-
for iKey=1:numel(expParameters.responseKey)
66-
fprintf('\n%s', expParameters.responseKey{iKey});
60+
for iKey=1:numel(cfg.keyboard.responseKey)
61+
fprintf('\n%s', cfg.keyboard.responseKey{iKey});
6762
end
6863
fprintf('\n\n');
6964
end
7065

7166

7267
%% Run demo
7368

69+
try
70+
7471
% Create the keyboard queue to collect responses.
75-
getResponse('init', cfg, expParameters, 1);
72+
getResponse('init', deviceNumber, cfg);
7673

7774
% Start collecting responses for 5 seconds
7875
% Each new key press is added to the queue of events recorded by KbQueue
7976
startSecs = GetSecs();
80-
getResponse('start', cfg, expParameters, 1);
77+
getResponse('start', deviceNumber);
8178

8279
% Here we wait for 5 seconds but are still collecting responses.
8380
% So you could still be doing something else (presenting audio and visual stim) and
8481
% still collect responses.
8582
WaitSecs(5);
8683

8784
% Check what keys were pressed (all of them)
88-
responseEvents = getResponse('check', cfg, expParameters, 0);
89-
90-
% The following line would only return key presses and not releases
91-
% responseEvents = getResponse('check', cfg, expParameters, 1);
85+
% If the escapeKey was pressed at any time, it will only abort when you
86+
% getResponse('check')
87+
responseEvents = getResponse('check', deviceNumber, cfg, getOnlyPress);
9288

9389
% This can be used to flush the queue: empty all events that are still present in the queue
94-
getResponse('flush', cfg, expParameters, 1);
90+
getResponse('flush', deviceNumber);
91+
92+
% If you wan to stop listening to key presses. You could start listening again
93+
% later by calling: getResponse('start', deviceNumber)
94+
getResponse('stop', deviceNumber);
9595

96-
% If you wan to stop listening to key presses.
97-
getResponse('stop', cfg, expParameters, 1);
96+
% If you wan to destroyt the queue: you would have to initialize it again
97+
getResponse('release', deviceNumber);
9898

9999

100100
%% Now we look what keys were pressed and when
@@ -106,9 +106,29 @@
106106
eventType = 'released';
107107
end
108108

109-
fprintf('\n%s was %s at time %.3f seconds\n', ...
109+
fprintf('\n %s was %s at time %.3f seconds\n', ...
110110
responseEvents(iEvent).key_name, ...
111111
eventType, ...
112112
responseEvents(iEvent).onset - startSecs);
113113

114114
end
115+
116+
117+
catch ME
118+
119+
getResponse('release', deviceNumber)
120+
121+
switch ME.identifier
122+
123+
case 'getResponse:abortRequested'
124+
warning('You pressed the escape key: will try to fail gracefully.')
125+
126+
fprintf('\nWe did catch your abort signal.\n')
127+
128+
otherwise
129+
rethrow(ME) % display other errors
130+
131+
end
132+
end
133+
134+

errorAbortGetReponse.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
function errorAbortGetReponse
2+
3+
errorStruct.message = 'Escape key press detected by getResponse: aborting experiment.';
4+
errorStruct.identifier = 'getResponse:abortRequested';
5+
6+
error(errorStruct)
7+
end

errorRestrictedKeysGetReponse.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
function errorRestrictedKeysGetReponse
2+
3+
errorStruct.message = 'getResponse reported a key press on a restricted key';
4+
errorStruct.identifier = 'getResponse:restrictedKey';
5+
6+
error(errorStruct)
7+
end

tests/getResponseTest.m

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
addpath(fullfile(pwd, '..'))
2+
3+
clear;
4+
clc;
5+
6+
if IsOctave
7+
more off % for a better display experience
8+
end
9+
10+
cfg = setDefaultsPTB;
11+
12+
%% Set parameters
13+
14+
% Decide which device you want to collect responses from
15+
deviceNumber = []; % default device (PTB will find it for you)
16+
17+
cfg.keyboard.responseKey = {'a', 'b'};
18+
cfg.keyboard.responseKey{end+1} = cfg.keyboard.escapeKey;
19+
20+
21+
%% Final checks
22+
23+
getOnlyPress = 1;
24+
25+
% Make sure keyboard mapping is the same on all supported operating systems
26+
KbName('UnifyKeyNames');
27+
28+
fprintf('\nDuring the next 5 seconds we will collect responses on the following keys: \n\n');
29+
if isempty(cfg.keyboard.responseKey)
30+
fprintf('\nALL KEYS\n\n');
31+
else
32+
for iKey=1:numel(cfg.keyboard.responseKey)
33+
fprintf('\n%s', cfg.keyboard.responseKey{iKey});
34+
end
35+
fprintf('\n\n');
36+
end
37+
38+
39+
%% Run manual test
40+
try
41+
42+
getResponse('init', deviceNumber, cfg);
43+
44+
getResponse('start', deviceNumber);
45+
46+
WaitSecs(5);
47+
48+
responseEvents = getResponse('check', deviceNumber, cfg, getOnlyPress);
49+
50+
getResponse('release', deviceNumber);
51+
52+
53+
%if some keys were pressed and that we are supposed to listen to only some
54+
%keys, we make sure that only those keys were listened to
55+
56+
if ~isempty(cfg.keyboard.responseKey) && isfield(responseEvents, 'keyName')
57+
58+
for iEvent = 1:size(responseEvents, 1)
59+
fprintf(' %s was pressed\n ', ...
60+
responseEvents(iEvent).keyName);
61+
62+
if ~any(strcmp({responseEvents(iEvent).keyName}, cfg.keyboard.responseKey))
63+
errorRestrictedKeysGetReponse();
64+
end
65+
end
66+
67+
end
68+
69+
catch ME
70+
71+
switch ME.identifier
72+
case 'getResponse:restrictedKey'
73+
rethrow(ME)
74+
75+
otherwise
76+
getResponse('release', deviceNumber);
77+
78+
rethrow(ME)
79+
end
80+
81+
end

0 commit comments

Comments
 (0)