File: GetClicks.m

package info (click to toggle)
psychtoolbox-3 3.0.19.14.dfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 86,796 kB
  • sloc: ansic: 176,245; cpp: 20,103; objc: 5,393; sh: 2,753; python: 1,397; php: 384; makefile: 193; java: 113
file content (158 lines) | stat: -rw-r--r-- 6,120 bytes parent folder | download
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
function [clicks,x,y,whichButton,clickSecs] = GetClicks(w, interClickSecs, mouseDev, untilTime)
% [clicks,x,y,whichButton,clickSecs] = GetClicks([windowPtrOrScreenNumber][, interclickSecs][, mouseDev][, untilTime=inf])
%
% Wait for the user to click the mouse, and then count the number of clicks
% that occur within a inter-click interval of each other. Return the number
% of 'clicks' and the mouse location 'x', 'y', as well as the indices of the
% pressed buttons in vector 'whichButton', and a vector 'clickSecs' with
% the timestamps of when each click was detected.
%
% The x,y location is the location at the downstroke of the first mouse
% click. The mouse position (x,y) is "local", i.e. relative to the origin of
% the window or screen, if supplied; otherwise it's "global", i.e. relative
% to the origin of the desktop.
%
% The allowed inter-click interval can be adjusted by setting the Matlab
% global variable "ptb_mouseclick_timeout" to a value in seconds. E.g.,
% global ptb_mouseclick_timeout; ptb_mouseclick_timeout = 1; would set the
% inter-click interval to 1 second. By default, the interval is 500 msecs.
%
% You can also specify an override interval in the optional argument
% 'interClickSecs' for a given call to GetClicks. A setting of zero would
% disable multi-click detection, ie., only wait for first mouse-click or
% press, then return immediately.
%
% If the optional parameter 'untilTime' is provided, GetClicks will only wait
% for the first click until that time and then return, regardless if the 1st click
% happened or not. On such a timeout, all return arguments will be zero. E.g.,
% [clicks,x,y,whichButton,clickSecs] = GetClicks(window, 0.2, [], GetSecs + 5);
% would wait up to 5 seconds in total for the first click to happen, and then
% another 0.2 seconds for a 2nd click, then 0.2 seconds for a 3rd click...
%
% The optional 'mouseDev' parameter allows to select a specific mouse or
% pointer device to query if your system has multiple pointer devices.
% Currently Linux only, silently ignored on other operating systems.
%
% See Also: GetMouse, SetMouse, GetMouseIndices

% 5/12/96  dgp  Wrote it.
% 5/16/96  dhb  Wrote as MEX-file, updated help.
% 6/7/96   dhb  Modified as per Pelli suggestion to respond to cmd-.
%          dhb  Modified as per Pelli suggestion to stop any playing sound.
% 8/23/96  dhb  Added support for windowPtr argument.
% 3/10/97  dgp  windowPtrOrScreenNumber
% 6/10/02  awi  Added See Also.
% 2/28/06  mk   Completely rewritten as a wrapper around GetMouse, based on
%          mk   the semantic and description of OS-9 GetClicks().
% 6/17/06  mk   We also pass the windowPtr - argument on Windows now, because
%          mk   now GetMouse.m is able to accept this argument.
% 02/08/09 mk   Report id of pressed button, allow for variable interclick,
%               as suggested by Diederick Niehorster. Reduce rtwait to 2
%               msecs but use WaitSecs('YieldSecs') waits to prevent
%               overload.
% 07/29/11 mk   Allow specification of 'mouseDev' mouse device index.
% 02/28/22 mk   Add 1st click timeout 'untilTime', and 'clickSecs' timestamps.

% Inter-click interval (in secs.) for multiple mouse-clicks.
global ptb_mouseclick_timeout;

% Setup default click timeout if no one set:
if isempty(ptb_mouseclick_timeout)
    ptb_mouseclick_timeout = 0.5; % Default timeout for multi-clicks is 500 msecs.
end

if nargin < 2
    interClickSecs = [];
end

if isempty(interClickSecs)
    interClickSecs = ptb_mouseclick_timeout;
end

if nargin < 3
    mouseDev = [];
end

if nargin < 4 || isempty(untilTime)
    untilTime = inf;
end

% Are we in nice mode?
nice = 1;

% Amount of secs to wait in nice-mode between each poll to avoid overloading
% the system. Now that WaitSecs('YieldSecs') is able to do a non-precise
% wait where it yields the cpu for at least the given amount of time, we
% can use rather strict/short wait intervals without the danger of
% overloading the system, so no need to differentiate between OS:
rtwait = 0.001; % 1 msecs yielding, ie., could take a bit longer.

% Wait for release of buttons if some already pressed:
buttons = 1;
while any(buttons) && (GetSecs < untilTime)
    [x,y,buttons] = GetMouse([], mouseDev);
    if ((nice > 0) && any(buttons)), WaitSecs('YieldSecs', rtwait); end
end

if any(buttons)
    % Timed out:
    [clicks, x, y, whichButton, clickSecs] = deal(0);
    return;
end

% Wait for first mouse button press:
while ~any(buttons) && (GetSecs < untilTime)
    if nargin < 1
        % Don't pass windowPtr argument if none supplied.
        [x,y,buttons] = GetMouse;
    else
        % Pass windowPtr argument to GetMouse for proper remapping.
        [x,y,buttons] = GetMouse(w, mouseDev);
    end
    if ((nice > 0) && ~any(buttons)), WaitSecs('YieldSecs', rtwait); end
end

if ~any(buttons)
    % Timed out:
    [clicks, x, y, whichButton, clickSecs] = deal(0);
    return;
end

% Timestamp 1st click:
clickSecs = GetSecs;

% First mouse click done. (x,y) is our returned mouse position. Assign
% button number(s) of clicked button(s) as well:
whichButton = find(buttons);

% Wait for further click in the timeout interval.
clicks = 1;
tend = clickSecs + interClickSecs;

while GetSecs < tend
    % If already down, wait for release...
    while any(buttons) && GetSecs < tend
        [xd,yd,buttons] = GetMouse([], mouseDev);
        if ((nice > 0) && any(buttons)), WaitSecs('YieldSecs', rtwait); end
    end

    % Wait for a press or timeout:
    while ~any(buttons) && GetSecs < tend
        [xd,yd,buttons] = GetMouse([], mouseDev);
        if ((nice > 0) && ~any(buttons)), WaitSecs('YieldSecs', rtwait); end
    end

    % Mouse click or timeout?
    if any(buttons) && GetSecs < tend
        % Mouse click. Count it.
        clicks = clicks + 1;

        % Timestamp and extend timeout for the next mouse click:
        clickSecs(end+1) = GetSecs;
        tend = clickSecs(end) + interClickSecs;
    end
end

% At this point, (x,y) contains the mouse-position of the first click
% and clicks should contain the total number of distinctive mouse clicks.
return;