Skip to content

Commit 654c1a4

Browse files
committed
initial commit
0 parents  commit 654c1a4

File tree

9 files changed

+588
-0
lines changed

9 files changed

+588
-0
lines changed

CPP_getResponseDemo.m

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
jk%% Demo showing how to use the getResponse function
2+
3+
% This small script shows how to use the getReponse function
4+
% (a wrapper around the KbQueue function from PTB)
5+
6+
% start with a clean slate
7+
clear; clc;
8+
if IsOctave
9+
more off % for a better display experience
10+
end
11+
12+
%% set parameters
13+
14+
% cfg.responseBox would be the device number of the device used by the participant to give his/her
15+
% response: like the button box in the scanner or a separate keyboard for a behavioral experiment
16+
%
17+
% cfg.keyboard would be the device number of the keyboard on which the experimenter will type or
18+
% press the keys necessary to start or abort the experiment.
19+
20+
% cfg.responseBox and cfg.keyboard can be different or the same.
21+
22+
% If you want to know the device number of all the keyboards and responses
23+
% boxes connected to the computer you can use the following code.
24+
% [cfg.keyboardNumbers, cfg.keyboardNames] = GetKeyboardIndices
25+
26+
% Using empty vectors should work for linux when to select the "main"
27+
% keyboard. You might have to try some other values for Windows. To
28+
% assigne a specific keyboard input the kb assigned value (see README)
29+
cfg.keyboard = [];
30+
cfg.responseBox = [];
31+
32+
% We set which keys are "valid", any keys other than those will be ignored
33+
expParameters.responseKey = {};
34+
35+
36+
%% init
37+
38+
% Keyboard
39+
% Make sure keyboard mapping is the same on all supported operating systems
40+
% Apple MacOS/X, MS-Windows and GNU/Linux:
41+
KbName('UnifyKeyNames');
42+
43+
44+
% we ask PTB to tell us which keyboard devices are connected to the computer
45+
[cfg.keyboardNumbers, cfg.keyboardNames] = GetKeyboardIndices;
46+
47+
cfg.keyboardNumbers
48+
cfg.keyboardNames
49+
50+
51+
% Test that the keyboards are correctly configured
52+
testKeyboards(cfg);
53+
54+
% Give the time to the test key to be released and not listened
55+
WaitSecs(1);
56+
57+
58+
fprintf('\nDuring the next 5 seconds we will collect responses on the following keys: \n\n');
59+
if isempty(expParameters.responseKey)
60+
fprintf('\nALL KEYS\n\n');
61+
else
62+
for iKey=1:numel(expParameters.responseKey)
63+
fprintf('\n%s', expParameters.responseKey{iKey});
64+
end
65+
fprintf('\n\n');
66+
end
67+
68+
69+
70+
%% Run demo
71+
72+
% Create the keyboard queue to collect responses.
73+
getResponse('init', cfg, expParameters, 1);
74+
75+
% Start collecting responses for 5 seconds
76+
% Each new key press is added to the queue of events recorded by KbQueue
77+
startSecs = GetSecs();
78+
getResponse('start', cfg, expParameters, 1);
79+
80+
81+
82+
% Here we wait for 5 seconds but are still collecting responses.
83+
% So you could still be doing something else (presenting audio and visual stim) and
84+
% still collect responses.
85+
WaitSecs(5);
86+
87+
88+
89+
% Check what keys were pressed (all of them)
90+
responseEvents = getResponse('check', cfg, expParameters, 0, 1);
91+
92+
% The following line would only return key presses and not releases
93+
% responseEvents = getResponse('check', cfg, expParameters, 1 , 1);
94+
95+
% This can be used to flush the queue: empty all events that are still present in the queue
96+
getResponse('flush', cfg, expParameters, 1);
97+
98+
% If you wan to stop listening to key presses.
99+
getResponse('stop', cfg, expParameters, 1);
100+
101+
102+
103+
104+
%% Now we look what keys were pressed and when
105+
for iEvent = 1:size(responseEvents, 1)
106+
107+
if responseEvents(iEvent).pressed
108+
eventType = 'pressed';
109+
else
110+
eventType = 'released';
111+
end
112+
113+
fprintf('%s was %s at time %.3f seconds\n', ...
114+
responseEvents(iEvent).key_name, ...
115+
eventType, ...
116+
responseEvents(iEvent).onset - startSecs);
117+
118+
end

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# CPP_PTB
2+
3+
List of PsychToolBox (PTB) related functions for the Crossmodal Perpcetion and Plasticity lab (CPP)
4+
5+
Most of the functions here are mostly wrappers around some PTB functions to facilitate their use and to have a codebase to facilitate their reuse.
6+
7+
## Code guidestyle
8+
9+
We use the `pascalCase` to more easily differentiates our functions from the ones from PTB that use a `CamelCase`.
10+
11+
## Structure and function details
12+
13+
### setParameters
14+
15+
### initPTB
16+
17+
### getResponse
18+
It is wrapper function to use KbQueue which is definitely what you should used to collect responses.
19+
20+
You can easily collect responses while running some other code at the same time.
21+
22+
It will only take responses from the `response box` which can simply be the "main keyboard" or another keyboard connected to the computer or the response box that the participant is using.
23+
24+
You can use it in a way so that it only takes responses from certain keys.
25+
26+
If you want to know more on how to use it check its help section and the `CPP_getResponseDemo.m`.
27+
28+
To select a specific keyboard to be used by experimenter/participant, you need to know the assigned MATLAB value. To copy-paste this on the command wuindow:
29+
30+
```
31+
[keyboardNumbers, keyboardNames] = GetKeyboardIndices;
32+
33+
keyboardNumbers
34+
keyboardNames
35+
```
36+
37+
38+
### cleanUp

cleanUp.m

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function cleanUp
2+
3+
WaitSecs(0.5);
4+
5+
Priority(0);
6+
7+
ListenChar(0);
8+
KbQueueRelease();
9+
10+
ShowCursor
11+
12+
% Screen Close All
13+
sca;
14+
15+
if ~ismac
16+
% remove PsychDebugWindowConfiguration
17+
clear Screen
18+
end
19+
20+
close all
21+
22+
23+
end

deg2Pix.m

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function structure = deg2Pix(fieldName, structure, Cfg)
2+
3+
deg = getfield( structure, fieldName);
4+
5+
structure = setfield( structure, [fieldName 'Pix'], ...
6+
floor(Cfg.ppd * deg) ) ;
7+
8+
end

drawFixationCross.m

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
function drawFixationCross(Cfg, ExpParameters, color)
2+
3+
Screen('DrawLines', ...
4+
Cfg.win, ...
5+
Cfg.allCoords, ...
6+
ExpParameters.lineWidthPix, ...
7+
color , ...
8+
[Cfg.center(1) Cfg.center(2)], 1);
9+
10+
end

getResponse.m

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
function responseEvents = getResponse(action, cfg, expParameters, getOnlyPress, verbose)
2+
% wrapper function to use KbQueue
3+
% The queue will be listening to key presses on the response box as defined
4+
% in the cfg structure : see setParameters for more details.
5+
%
6+
% Check the CPP_getResponseDemo for a quick script on how to use it.
7+
%
8+
%
9+
%
10+
% INPUT
11+
%
12+
% - action: Defines what we want the function to do
13+
% - init: to initialise the queue
14+
% - start: to start listening to keypresses
15+
% - check:
16+
% - flush:
17+
% - stop:
18+
%
19+
% - getOnlyPress: if set to 1 the function will only return the key presses and
20+
% will not return when the keys were released (default=1)
21+
% See the section on OUTPUT below for more info
22+
%
23+
%
24+
%
25+
% OUTPUT
26+
%
27+
% responseEvents: returns all the keypresses and return them as a structure
28+
% with field names that make it easier to save the output of in a BIDS
29+
% format
30+
%
31+
% responseEvents.onset : this is an absolute value and you should
32+
% substract the "experiment start time" to get a value relative to when the
33+
% experiment was started.
34+
%
35+
% responseEvents.trial_type = 'response';
36+
%
37+
% responseEvents.duration = 0;
38+
%
39+
% responseEvents.key_name : the name of the key pressed
40+
%
41+
% responseEvents(iEvent,1).pressed : if
42+
% pressed == 1 --> the key was pressed
43+
% pressed == 0 --> the key was released
44+
45+
46+
if nargin < 4
47+
getOnlyPress = 1;
48+
end
49+
50+
if nargin < 5
51+
verbose = 0;
52+
end
53+
54+
responseEvents = struct;
55+
responseEvents.onset = [];
56+
responseEvents.trial_type = [];
57+
responseEvents.duration = [];
58+
responseEvents.key_name = [];
59+
responseEvents.pressed = [];
60+
61+
responseBox = cfg.responseBox;
62+
63+
switch action
64+
65+
case 'init'
66+
67+
% Prevent spilling of keystrokes into console. If you use ListenChar(2)
68+
% this will prevent you from using KbQueue.
69+
ListenChar(-1);
70+
71+
% Clean and realease any queue that might be opened
72+
KbQueueRelease(responseBox);
73+
74+
%% Defines keys
75+
% list all the response keys we want KbQueue to listen to
76+
77+
% by default we listen to all keys
78+
% but if responseKey is set in the parameters we override this
79+
keysOfInterest = ones(1,256);
80+
81+
fprintf('\n Will be listening for key presses on : ')
82+
83+
if isfield(expParameters, 'responseKey') && ~isempty(expParameters.responseKey)
84+
85+
keysOfInterest = zeros(1,256);
86+
87+
for iKey = 1:numel(expParameters.responseKey)
88+
fprintf('\n - %s ', expParameters.responseKey{iKey})
89+
responseTargetKeys(iKey) = KbName(expParameters.responseKey(iKey)); %#ok<*SAGROW>
90+
end
91+
92+
keysOfInterest(responseTargetKeys) = 1;
93+
94+
else
95+
96+
fprintf('ALL KEYS.')
97+
98+
end
99+
100+
fprintf('\n\n')
101+
102+
% Create the keyboard queue to collect responses.
103+
KbQueueCreate(responseBox, keysOfInterest);
104+
105+
106+
case 'start'
107+
108+
fprintf('\n starting to listen to keypresses\n')
109+
110+
KbQueueStart(responseBox);
111+
112+
113+
case 'check'
114+
115+
if verbose
116+
fprintf('\n checking recent keypresses\n')
117+
end
118+
119+
iEvent = 1;
120+
121+
while KbEventAvail(responseBox)
122+
123+
event = KbEventGet(responseBox);
124+
125+
% we only return the pressed keys by default
126+
if getOnlyPress && event.Pressed==0
127+
else
128+
129+
responseEvents(iEvent,1).onset = event.Time;
130+
responseEvents(iEvent,1).trial_type = 'response';
131+
responseEvents(iEvent,1).duration = 0;
132+
responseEvents(iEvent,1).key_name = KbName(event.Keycode);
133+
responseEvents(iEvent,1).pressed = event.Pressed;
134+
135+
end
136+
137+
iEvent = iEvent + 1;
138+
139+
end
140+
141+
case 'flush'
142+
143+
if verbose
144+
fprintf('\n reinitialising keyboard queue\n')
145+
end
146+
147+
KbQueueFlush(responseBox);
148+
149+
150+
case 'stop'
151+
152+
fprintf('\n stopping to listen to keypresses\n\n')
153+
154+
KbQueueRelease(responseBox);
155+
156+
% Give me my keyboard back... Pretty please.
157+
ListenChar(0);
158+
159+
end
160+
161+
162+
end

0 commit comments

Comments
 (0)