/usr/share/psychtoolbox-3/PsychBasic/RemapMouse.m is in psychtoolbox-3-common 3.0.14.20170103+git6-g605ff5c.dfsg1-1build1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 | function [xo, yo] = RemapMouse(win, viewId, xm, ym)
% [xo, yo] = RemapMouse(win, viewId, xm, ym); -- Map mouse position to stimulus position.
%
% Certain operations, e.g., PsychImaging('AddTask', ..., 'GeometryCorrection', ...);
% to perform geometric display correction, will break the 1:1
% correspondence between stimulus pixel locations (xo,yo) and the mouse
% cursor position, ie. a mouse cursor positioned at display position
% (xm,ym) will be no longer pointing to stimulus pixel (xm,ym). If you
% want to know which pixel in your original stimulus image corresponds to
% a specific physical display pixel (or mouse cursor position), use this
% function to perform the neccessary coordinate transformation.
%
% 'win' is the window handle of the onscreen window to remap.
%
% 'viewId' is the view id to remap, the same name you specified in
% PsychImaging() to setup a geometry correction, e.g., 'AllViews'.
%
% (xm,ym) is the 2D position in display device space, e.g., as returned
% from GetMouse() for a mouse cursor position query. Please make sure
% that you pass in the 'win'dow handle to GetMouse as well, ie.
% GetMouse(win), so GetMouse() can correct its returned mouse position
% for your specific display arrangement and onscreen window placement.
% This function only corrects for distortions inside the onscreen window
% 'win', ie. relative to its origin.
%
% The returned values (xo, yo) are the remapped stimulus pixel locations,
% over which a mouse cursor at location (xm,ym) is currently hovering.
%
% If you pass in a (xm,ym) position for which there doesn't exist any
% corresponding stimulus pixel position, the values (0,0) will be
% returned.
%
% If you call this function on a window or view without active geometry
% manipulations, it will do nothing and simply return the passed in (xm,
% ym) position, ie. it is safe to use this function all the time.
%
% Limitations: The function currently only corrects for distortions
% introduced by the tasks implemented in the Psychtoolbox image
% processing pipeline via some of the functions available via
% PsychImaging() function. It does not take other transformations into
% account, e.g., mirroring, arranging displays of a multi-display setup
% in an unusual way etc. You may need to add your own code to take such
% transformations into account.
%
% History:
% 26.12.2011 mk Written.
% 12.01.2013 mk Added panelfitter support.
% 04.11.2014 mk Handle Retina modes on OSX and rotation via panelfitter.
% This global array is setup by PsychImaging() when setting up geometric
% display correction:
global ptb_geometry_inverseWarpMap;
if nargin < 4
error('At least one of the required parameters is missing!');
end
if ~isnumeric(win) || ~isscalar(win) || (Screen('WindowKind', win) ~= 1)
error('Window handle invalid. Does not correspond to an onscreen window!');
end
if ~ischar(viewId)
error('viewId parameter is not a name string, as required!');
end
% OSX reports mouse position in points, not pixels, but our
% code expects pixels. Compute backing store scale factor
% (for Retina / HiDPI displays) and undo its effect on (x,y) position:
if IsOSX
screenNumber = Screen('WindowScreenNumber', win);
isf = Screen('WindowSize', screenNumber, 1) / Screen('WindowSize', screenNumber, 0);
% OSX reports mouse position in points, but we need
% it in pixels, so multiply:
xm = xm * isf;
ym = ym * isf;
end
if isempty(ptb_geometry_inverseWarpMap) || isempty(ptb_geometry_inverseWarpMap{win})
% Window does not use geometry correction. Just pass-through our input values:
xo = xm;
yo = ym;
else
% Apply gains and modulo transform to input (xm,ym):
xm = mod(xm * ptb_geometry_inverseWarpMap{win}.gx, ptb_geometry_inverseWarpMap{win}.mx);
ym = mod(ym * ptb_geometry_inverseWarpMap{win}.gy, ptb_geometry_inverseWarpMap{win}.my);
if ~isfield(ptb_geometry_inverseWarpMap{win}, viewId)
% No inverse map, we're almost done:
xo = xm;
yo = ym;
else
% Retrieve proper inverse mapping matrix for given viewId:
map = ptb_geometry_inverseWarpMap{win}.(viewId);
% Round and map (xm,ym) input mouse position to indices in inverse map:
xm = min(max(round(xm) + 1, 1), size(map, 2));
ym = min(max(round(ym) + 1, 1), size(map, 1));
% Lookup corresponding unmapped position from matrix:
xo = double(map(ym, xm, 1));
yo = double(map(ym, xm, 2));
end
end
% At this point (xo, yo) contain mouse position relative to the imaging
% pipelines image buffer for the requested viewId. If remapping wrt. some
% internal buffer or final buffer was requested, we're done. For the most
% common case of remapping to the stimulus input buffer, we need one more
% step:
if strcmpi(viewId, 'AllViews') || strcmpi(viewId, 'LeftView') || strcmpi(viewId, 'RightView')
% Want mouse position mapped to original stimulus image. The current
% (xo, yo) contains mouse position wrt. inputBufferFBO for viewId. If
% our gpu panel scaler is active then we need to undo the rescaling
% done by the scaler to get the position in the drawBufferFBO which
% corresponds to our effective stimulus position. Query panel fitter
% parameters into p:
p = Screen('PanelFitter', win);
% Panelfitter active aka p non-zero?
if any(p)
% Remap:
% Non-Zero rotation angle?
if p(9) ~= 0
% Yes, need some extra rotation inversion transforms:
xoff = p(5); yoff = p(6);
cx = p(10); cy = p(11);
angle = p(9);
xo = xo - (xoff + cx);
yo = yo - (yoff + cy);
rot = atan2(yo, xo) - (angle * pi / 180);
rad = norm([yo, xo]);
xo = rad * cos(rot);
yo = rad * sin(rot);
xo = xo + (xoff + cx);
yo = yo + (yoff + cy);
end
% Invert scaling and offsets:
xo = ((xo - p(5)) / (p(7) - p(5)) * (p(3) - p(1))) + p(1);
yo = ((yo - p(6)) / (p(8) - p(6)) * (p(4) - p(2))) + p(2);
end
end
return;
|