-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAdjustmentStimulus.m
140 lines (118 loc) · 4.58 KB
/
AdjustmentStimulus.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
classdef (Abstract) AdjustmentStimulus < Task
%ADJUSTMENTSTIMULUS Interface for method-of-adjustment stimuli
% Generic - override me
properties
CurrValue
end
properties(Abstract)
initValue
end
properties(Constant)
stopKey = 'return'; % FIXME hack
end
methods(Static)
function columns = getColumns(varargin)
if nargin < 1
columns = [getColumns@Task(), ...
{'Final value', 'Initial value'}];
else
unitText = varargin{1};
columns = [getColumns@Task(), ...
{sprintf('Final value (%s)', unitText), ...
sprintf('Initial value (%s)', unitText)}];
end
end
end
methods
function data = collectFlatData(t)
data = [t.collectFlatData@Task(), t.Result, t.initValue];
end
end
methods
function [success, result] = runOnce(self)
HWRef = HWReference();
HW = HWRef.hw;
self.CurrValue = self.initValue;
stop = false;
% wait until all keys and mouse are released
[~,~,buttons] = GetMouse();
mouseDown = any(buttons);
keyDown = KbCheck();
while mouseDown || keyDown
[~,~,buttons] = GetMouse();
mouseDown = any(buttons);
keyDown = KbCheck();
end
wasKeyUp = false;
% Set cursor to (near) the center
mousePtr = HW.screenNum;
scrCenter = round(0.5*[HW.width HW.height]);
scrCtrX = scrCenter(1);
scrCtrY = scrCenter(2);
SetMouse(scrCtrX, scrCtrY, mousePtr);
while ~stop
% Present new stimulus frame
self.draw();
% Process response
[keyDown, ~, keyCode, ~] = KbCheck();
downstroke = keyDown && wasKeyUp;
if downstroke
response = KbName(keyCode);
else
response = [];
end
if downstroke && ~iscell(response)
switch lower(response)
case HW.upKey
self.goUp();
case HW.downKey
self.goDown();
case self.stopKey
stop = self.stopCheck();
case HW.haltKey
% 'graceful' bail
throw(MException('FindThreshold:Halt', ...
['Halted by user hitting ''' ...
HW.haltKey '''!']));
otherwise
% That wasn't one of the valid keys!
PsychPortAudio('Start', HW.failSoundHandle);
% TODO display message to user?
end
end
wasKeyUp = ~keyDown;
% Look for displacement in mouse, then reset it
[mouseX, mouseY, buttons] = GetMouse(mousePtr);
mouseVec = [mouseX - scrCtrX, mouseY - scrCtrY];
if buttons(1)==1
stop = self.stopCheck();
else
self.handleMouse(mouseVec);
end
SetMouse(scrCtrX, scrCtrY, mousePtr);
end
success = true;
result = self.CurrValue;
self.Completed = true;
self.Result = result;
self.runOnce@Task();
end
end
methods (Abstract)
% Function called every frame to refresh the screen
[] = draw(task);
% Function called each time the subject presses HW.upKey
[] = goUp(task);
% Function called each time the subject presses HW.downKey
[] = goDown(task);
% Function called every frame on mouse position changes
% Arguments:
% vector = [x,y] pixel vector of mouse movement this frame
% Relative movement only, one frame at a time
% Mouse is reset to the middle of the frame after this call
[] = handleMouse(task, vector);
% Function called when the subject says they are finished
% Returns true iff the task should stop / is completed
[stop] = stopCheck(task);
end
end