File: ListenChar.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 (340 lines) | stat: -rw-r--r-- 15,740 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
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;