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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
|
function ListenChar(listenFlag)
% function ListenChar([listenFlag])
%
% Tell the Psychtoolbox function "GetChar" to start or stop listening for
% keyboard input. By default ListenChar enables listening when no argument is
% supplied. Passing 0 will turn off character listening and reset the
% buffer which holds the captured characters. Passing a value of 1 or not
% passing any value will enable listening. Passing a value of 2 will enable
% listening, additionally any output of keypresses to Matlabs or Octaves
% windows is suppressed. Use this with care, if your script aborts with an
% error, Matlab or Octave may be left with a dead keyboard until the user
% presses CTRL+C to re-enable keyboard input. 'listenFlag' 2 is silently
% ignored on Matlab in -nojvm mode under MS-Windows.
%
% Passing the listenFlag -1 will only suppress keypresses into Matlabs or
% Octaves command window, but not collect characters for use with CharAvail
% or GetChar. This allows concurrent use of ListenChar for character suppression
% while at the same time using keyboard queues for character and key input.
% Reenabling keypresses into Matlab and Octave is only possible via a call
% with listenFlag 0 if suppression was enabled with listenFlag -1. Use of
% listenFlag -1 does not block keyboard queues, so if you want to get keyboard
% input, the better way might be to use keyboard queues (see KbEventAvail,
% KbEventGet and KbEventFlush) for input and ListenChar(-1) and ListenChar(0)
% to suppress characters into the Matlab/Octave command window or console.
%
% This function isn't entirely necessary to turn on listening as calling
% GetChar, CharAvail, or FlushEvents will trigger listening on. However,
% it is the only method by which to disable listening or switch between
% suppression of keyboard input to Matlab and unsuppressed mode.
%
% Please note that the commands ListenChar, CharAvail and GetChar are
% subject to various constraints and limitations, depending on the
% operating system you use, if you use Matlab in Java or -nojvm mode, if
% you use Octave, if you have Screen() onscreen windows open or not, or if
% you use KbQueueXXX functions in parallel or not. Therefore use of these
% functions can be troublesome for any but the most simple usages. Use of
% KbCheck, KbWait, KbStroke/Press/ReleaseWait is often simpler if you are
% just after keyboard input. Use of KbQueue functions, e.g., KbQueueCheck,
% KbQueueWait, KbTriggerWait is better suited for background keystroke
% collection. Use of KbEventAvail and KbEventGet is often more convenient,
% more flexible and subject to less restrictions and gotchas than use of
% GetChar et al.
%
% Some of the restrictions and caveats:
%
% 1. Works very well with Matlab and its Java based GUI enabled on Linux (on
% desktop GUI's other than KDE) and macOS, as well as on WindowsXP and earlier
% versions of Windows.
%
% 2. When used on Windows Vista or later (Vista, Windows-7, ..., Windows-10)
% with Matlab's Java GUI, you cannot use any KbQueue functions at the same
% time, ie., KbQueueCreate/Start/Stop/Check/Wait as well as KbWaitTrigger,
% KbEventFlush, KbEventAvail, and KbEventGet are off limits after any call
% to ListenChar, ListenChar(1), ListenChar(2), FlushEvents, CharAvail or
% GetChar. You would need to call ListenChar(0) before you could call
% KbQueueCreate and then use those functions. Vice versa, after a call to
% KbQueueCreate, CharAvail, FlushEvents, and GetChar are dysfunctional and
% ListenChar may be limited. You need to call KbQueueRelease before you can
% use them again. Use of other devices, e.g., mouse or joystick, is not
% prohibited during use of GetChar et al.
%
% 3. If you use Matlab in "matlab -nojvm" mode without its GUI, or if you
% use GNU/Octave instead of Matlab, the same restrictions as in 2. apply -
% no parallel use of the default keyboards KbQueue. KbQueues can be used
% for other input devices and on Linux and OSX for keyboards other than the
% default keyboard.
%
% The only feature that works in parallel with KbQueues on the default keyboard
% is the suppression of spilling of keystroke characters into the Matlab or
% Octave window during ListenChar(2) - at least on Linux and OSX. On
% Windows this can't be prevented at all in "matlab -nojvm" mode. However,
% if you switch to ListenChar(2) mode, you cannot break out of it by
% pressing CTRL+C on Linux if the keyboard queue that is in parallel use
% didn't get KbQueueStart called, ie. if it is stopped. On OSX with a
% stopped Keyboard queue, neither CTRL+C nor stopping a runaway script
% works.
%
% 4. On Linux, as a exception, some GetChar, CharAvail functionality may
% still work in case 3. under certain conditions, e.g., if you don't use
% ListenChar(2) and your Matlab/Octave is not in interactive mode.
%
% Also, GetChar can only collect keystrokes from multiple connected
% keyboards in case 1. In all other cases, it can only collect keystrokes,
% or respond to press of CTRL+C, for the default keyboard device. It will
% ignore other connected keyboards.
%
% Another limitation in cases 2 and 3 is that international keyboards with non-US
% layout and non-ASCII/Latin-1 characters may need special treatment and Octave
% may have some trouble processing such characters. See "help KbEventGet" for a
% detailed explanation.
%
% Basically: Mixing GetChar et al. and modern KbQueue functions is usually
% not advisable, or if needed, great care must be taken to sidestep all the
% mentioned limitations. Also the KbQueue functions usually have better
% timing precision and allow to flexibly address multiple keyboards
% separately at least on Linux and OSX.
%
%
% For further explanation see help for "GetChar".
%
% _________________________________________________________________________
%
% See also: GetChar
% HISTORY
%
% 7/19/05 awi Wrote it.
% 6/20/06 awi Use AddPsychJavaPath instead of AssertGetCharJava.
% 8/31/06 cgb Works with the new character listening system.
% 9/19/06 mk Modified to work on all Java enabled Matlabs and be a no-op
% in all other configurations.
% 10/13/06 mk Support for setting the redispatch-mode of GetChar and
% friends.
% 05/31/09 mk Add support for Octave and Matlab in noJVM mode.
% 01/31/16 mk Add support for listenFlag -1 for only blocking input.
% 06/20/19 mk Try to protect against KDE focus stealing nastiness via kbqueues.
global OSX_JAVA_GETCHAR;
persistent keyboard_blocked;
if nargin == 0
listenFlag = 1;
elseif nargin > 1
error('Too many arguments to ListenChar! See "help ListenChar" for more information');
end
if ~ismember(listenFlag, [-1,0,1,2])
error('Invalid listenFlag provided! See "help ListenChar" for more information');
end
if isempty(keyboard_blocked)
keyboard_blocked = 0;
end
% Is this Matlab? Is the JVM running?
if psychusejava('desktop')
% Java enabled on Matlab. There's work to do.
% Make sure that the GetCharJava class is loaded.
if isempty(OSX_JAVA_GETCHAR)
try
OSX_JAVA_GETCHAR = AssignGetCharJava;
catch %#ok<*CTCH>
error('Could not load Java class GetCharJava! Read ''help PsychJavaTrouble'' for help.');
end
end
if listenFlag ~= 0
% Start listening for characters.
OSX_JAVA_GETCHAR.register;
% Make sure the Matlab window has keyboard focus:
if ~IsWinVista && exist('commandwindow') %#ok<EXIST>
% Call builtin implementation:
commandwindow;
drawnow;
end
% Should we block output of characters to Matlab?
if listenFlag > 1 || listenFlag == -1
% Disable redispatching:
OSX_JAVA_GETCHAR.setRedispatchFlag(1);
else
% Enable redispatching: This is the startup default.
OSX_JAVA_GETCHAR.setRedispatchFlag(0);
end
else
% Stop listening for characters and clear the buffer.
OSX_JAVA_GETCHAR.unregister;
OSX_JAVA_GETCHAR.clear;
% Enable redispatching:
OSX_JAVA_GETCHAR.setRedispatchFlag(0);
end
% On non-Vista we're done. On Vista and later, we fall-through to the
% fallback path below, as Java based GetChar() is only useful to
% suppress character output to the Matlab command window, aka clutter
% prevention, not for actually recording key strokes.
% If we are running on Linux with the KDE desktop GUI, we also need to
% use non-Java fallbacks for keystroke recording, as KDE's window manager
% has the nasty habit of removing keyboard input focus from the Matlab window,
% as soon as the onscreen window opens, so Java based GetChar doesn't get input.
if ~IsWinVista && isempty(getenv('KDE_FULL_SESSION'))
return;
end
% Windows Vista or later with Matlabs Java based GUI running.
% If only the keyboard was blocked via listenFlag -1 before and
% this is a unblock request via listenFlag 0 then we are done, as
% setRedispatchFlag() above has already done all the work.
if listenFlag == 0 && keyboard_blocked
keyboard_blocked = 0;
return;
end
% If just keyboard blocking was requested via listenFlag -1 then
% setRedispatchFlag() above has done all the work and we just need
% to note this in keyboard_blocked, other than that we are done.
if listenFlag == -1
keyboard_blocked = 1;
return;
end
end
% Running either on Octave with or without GUI, or on Matlab in No JVM mode,
% or on a MS-Vista system or later while user wants keyboard input.
% Does the user only want to block keyboard input from spilling into the
% command window / console, but not use GetChar et al.?
if listenFlag == -1
% Yes. No need for use of keyboard queues, only use low level tricks
% to prevent keyboard input on Octave or on Matlab nojvm.
keyboard_blocked = 1;
% LoadPsychHID is needed on MS-Windows. It no-ops if called redundantly:
LoadPsychHID;
% Disable character forwarding to console:
PsychHID('KeyboardHelper', -12);
return;
end
% Does the user only want to unblock keyboard input from spilling into the
% command window / console after blocking it before with listenFlag -1?
if listenFlag == 0 && keyboard_blocked
% Yes. Just re-enable keyboard input
keyboard_blocked = 0;
% LoadPsychHID is needed on MS-Windows. It no-ops if called redundantly:
LoadPsychHID;
% Re-enable character forwarding to console:
PsychHID('KeyboardHelper', -10);
return;
end
if keyboard_blocked
% Reset keyboard only blocked state on other transitions:
keyboard_blocked = 0;
end
% On all systems we prefer to (ab)use keyboard queues. This allows character
% suppression via ListenChar(2) to work at least on OSX and Linux and provides
% high robustness against keyboard focus changes. If we can't get the relevant
% keyboard queue on OSX or Windows at this point, we have to fail. However,
% if we are on Linux and the keyboard queue is already in use by usercode,
% we can fall back to 'GetMouseHelper' low-level terminal tty magic. The
% only downside is that typed characters will spill into the console, ie.,
% ListenChar(2) suppression is unsupported:
if ~IsLinux || ~KbQueueReserve(3, 2, [])
% We can use the default keyboard's keyboard queue - Good:
% LoadPsychHID is needed on MS-Windows. It no-ops if called redundantly:
LoadPsychHID;
if listenFlag > 0
% Only need to reserve/create/start queue if we don't have it
% already:
if ~KbQueueReserve(3, 1, [])
% Try to reserve default keyboard queue for our exclusive use:
if ~KbQueueReserve(1, 1, [])
% This is non-fatal, only worth a warning:
if IsOSX(1)
% OSX:
warning('PTB3:KbQueueBusy', 'Keyboard queue for default keyboard device already in use by KbQueue/KbEvent functions et al. Use of ListenChar(2) may work for keystroke suppression, but GetChar() etc. will not work.\n');
else
% 32-Bit OSX, or MS-Windows:
warning('PTB3:KbQueueBusy', 'Keyboard queue for default keyboard device already in use by KbQueue/KbEvent functions et al. Use of ListenChar/GetChar/CharAvail/FlushEvents etc. and keyboard queues is mutually exclusive!');
end
% We fall through to KeyboardHelper to enable input
% redirection on 64-Bit OSX. While our CharAvail() and
% GetChar() are lost causes, input redirection and CTRL+C
% can work if usercode has called KbQueueStart, as the
% users kbqueue-thread gives us a free-ride for our
% purpose.
else
% Got it. Allocate and start it:
PsychHID('KbQueueCreate');
PsychHID('KbQueueStart');
end
end
else
% Does default keyboard queue belong to us?
if KbQueueReserve(3, 1, [])
% Yes. Stop and release it:
PsychHID('KbQueueStop');
PsychHID('KbQueueRelease');
KbQueueReserve(2, 1, []);
end
end
if (listenFlag > 1) && (~IsOSX || ~IsOctave || IsGUI)
% Disable character forwarding to console:
PsychHID('KeyboardHelper', -12);
elseif (listenFlag == 1) && (IsOctave && IsGUI)
% Enable character forwarding to the runtime/console.
% This is special: We receive our characters via the KbQueues event
% buffer. At the same time, the runtime receives characters via
% stdin, which are fed by our Kbqueue and a special unix pipe:
PsychHID('KeyboardHelper', -11);
else
% Enable character forwarding to console,
% disable it for us, as we use keyboard
% queues, not tty magic:
PsychHID('KeyboardHelper', -10);
end
return;
end
% This fallback code is only executed on Linux as a last resort. It uses
% low-level tty magic to get some characters from the stdin stream of the
% controlling tty:
if listenFlag > 1
% Disable character forwarding to console: This will also prevent us
% from seeing any characters, as we can only see what the runtime aka
% stdin/tty sees - which is nothing. Can't use kbqueues to get the data
% as usual:
PsychHID('KeyboardHelper', -12);
warning('PTB3:KbQueueBusy', 'Keyboard queue for default keyboard device already in use by KbQueue/KbEvent functions et al.\nUse of ListenChar(2) may work for keystroke suppression, but GetChar() etc. will not work!\n');
elseif listenFlag == 1
% Enable character forwarding to the runtime/console. Runtime gets
% keystrokes and CTRL+C, but we will only get data via stdin/tty if the
% runtime doesn't steal characters from us, as we can't use kbqueues
% here:
PsychHID('KeyboardHelper', -11);
warning('PTB3:KbQueueBusy', 'Keyboard queue for default keyboard device already in use by KbQueue/KbEvent functions et al.\nUse of ListenChar(2) may work for keystroke suppression, but CharAvail()/GetChar() will not work reliably under all conditions!\n');
else
% Enable character forwarding to console. Runtime gets keystrokes and
% CTRL+C, but we will only get data via stdin/tty if the runtime
% doesn't steal characters from us, as we can't use kbqueues here:
PsychHID('KeyboardHelper', -10);
warning('PTB3:KbQueueBusy', 'Keyboard queue for default keyboard device already in use by KbQueue/KbEvent functions et al.\nUse of ListenChar(2) may work for keystroke suppression, but CharAvail()/GetChar() will not work reliably under all conditions!\n');
end
return;
|