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;
|