Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

PSYCH 20B (Prof. Frane) Part 3: Getting Instantaneous Keyboard Input

Check the Current Status of All Keys

The KbCheck function checks the keyboard and gives multiple outputs:

[anyKeyDown, keySecs, keyCode] = KbCheck(-1) ; % check key statuses

The first input to KbCheck is the “device number” identifying the keyboard we want to check. Typically we input a   device number of -1 (as we do above), which means “all device numbers.” That way, all connected keyboards are checked, and if there are multiple keyboards their output is merged.

anyKeyDown is a logical value: 1 if any key is down, and 0 otherwise.

keySecs is a timestamp (in seconds) marking the moment the keyboard is checked. This timestamp is not very meaningful in itself, but can be compared to some other timestamp to compute elapsed time in seconds.

keyCode is a vector of 256 logical values indicating the status of all 256 possible keys (showing 1 for each key that is down and 0 for each key that is up). You probably don’t have 256 keys on your keyboard, but that’s the maximum you theoretically could have, so that’s the number of values in the vector. The values in the vector are ordered by key-

number (each key on your keyboard is indentified by a unique key-number). So the indexes (positions) where the 1s are in the vector indicate the key-numbers of the specific keys that are currently down.

Thus, if you want to know which particular key is pressed, you can use the find function to identify which indexes in the keyCode vector have values of 1:

pressedKeyNum = find(keyCode==1) ; % key-number(s) of pressed key(s)

Or more simply:

pressedKeyNum = find(keyCode) ; % key-number(s) of pressed key(s)

Of course, knowing the key-number of the pressed key may not make it obvious to you which key was pressed, because you probably haven’t memorized which keys correspond to which key number. Moreover, the correspondence between key and key-number can vary from one system to another. But the section below explains how to get the key-name for a given key-number on your system.

Convert Between Key-Number and Key-Name

First of all, the exact spelling of key-names may vary from one system to another. Therefore, if you’re going to use    key-names at all in your program, it’s a good idea to force Psychtoolbox to use the standard OSX key-name system. That way, the key-names will be the same regardless of what computer you run your program on. You can do that    using the KbName function, by putting this line in the setup section of your program:

KbName('UnifyKeyNames') % use OSX key-name system

To get an idea of what the key-names look like, you can type KbName('KeyNames') into your command window to    output a cell array listing the key-names of all 256 keys, ordered by key-number. When I do that on my Macbook, I see that, for example, key #44 is named  'space ', key #80 is named  'LeftArrow ', and keys #4–29 correspond to the     letter-keys  'a ' through  'z '.

Inputting a key-number to KbName — for example typing KbName(40) — outputs the key-name that corresponds to that key-number. Thus, when used in combination with KbCheck, the KbName function can tell us the name of a

pressed key:

[anyKeyDown, keySecs, keyCode] = KbCheck(-1) ; % check status of all keys

pressedKeyNum  = find(keyCode)                ; % key-number(s) of pressed key(s)

pressedKeyName = KbName(pressedKeyNum)       ; % key-name(s)   of pressed key(s)

Typing KbName by itself, with no input arguments, will output the key-name of the next key that’s pressed (though you have to wait at least 1 second before pressing the key). This isn’t typically useful in a program, but it’s handy to use in

the command window when you want to verify the official key-name of a particular key. Don’t forget to use KbName('UnifyKeyNames') first.

You can also use the KbName function to convert a key-name to a corresponding key-number:

keyNumReturn = KbName('Return') ; % key-number(s) for 'Return' key

Note that the comment in the above line says key-number(s),” not “key-number.” That’s because some key-names     may be associated with more than one key-number. In such cases, it is typically the lowest of those key-numbers that actually applies to your keyboard. Thus, instead of the above line, I suggest the following:

keyNumReturn = min( KbName('Return') ) ; % key-number for 'Return' key

Wait for Any Key to Be Pressed

In Psych 20A, you may have learned to use the pause function to wait for a key to be pressed. However, if we

suppress keyboard output to the command window (as we typically do when using Psychtoolbox), then that won’t work. Instead, we can use KbCheck in a while-loop:

while ~KbCheck(-1) % wait for any key to be down

end

Note that ~KbCheck(-1) is equivalent to KbCheck(-1)==0.

Wait for All Keys to Be Up

Sometimes we want to wait for all keys to be up. For instance, that’s useful when we want to record multiple key-

presses in a row, and we don’t want any one key-press to be recorded multiple times because the finger is lingering     on the key. Or we might want to see how fast the user presses a key after being prompted, and we don’t want them to “cheat” by starting to hold down the key before the prompt. In such cases, we only want to register “fresh” key-

presses, so we wait for all keys to be up first:

while KbCheck(-1) % wait for all keys to be up

end

The KbWait Function

The KbWait function makes waiting for keys to be up or down a little simpler, because there’s a while-loop already built into the function. To wait for any key to be down, we can just say:

KbWait(-1) ; % wait for any key to be down

But KbWait is slower than KbCheck because it only checks the keyboard every 5 ms, whereas KbCheck checks the   keyboard as quickly as you can go through the while-loop (which is typically much faster than every 5 ms). So KbWait shouldn’t be used when you want fast responses to key-presses. Also, because KbWait doesn’t proceed to the next    line of code until a key is pressed, it doesn’t allow you do other things (such as changing a stimulus) while waiting.

With KbCheck, however, you can do additional things inside the while-loop as you wait.

The first input to KbWait is the keyboard device number, just like with KbCheck, so typically we input -1.

KbWait can be used in 4 different modes (by entering a 0, 1, 2, or 3 as the second input argument), as follows:

KbWait(-1, 0) ; % wait for any key to be down - equivalent to just KbWait(-1)

KbWait(-1, 1) ; % wait for all keys to be up - equivalent to KbReleaseWait(-1)

KbWait(-1, 2) ; % once all keys are up, wait for any key to be pressed

% equivalent to KbPressWait(-1)

KbWait(-1, 3) ; % once all keys up, wait for any key to be pressed and then released

% equivalent to KbStrokeWait(-1)

You can have KbWait return the same keySecs and keyCode outputs that we got from KbCheck,but the syntax for the output vector is slightly different because there’s no anykeyDown output:

[keySecs, keyCode] = KbWait(-1) ; % wait for any key to be pressed; get timestamp

% for key-press, and get vector of key-statuses

In KbWait modes 0, 2, and 3, secs is a timestamp marking the moment a key is first detected as being down. And in  KbWait mode 1, keySecs is a timestamp marking the moment a key is first detected as being up. But remember, the timestamps from KbWait are less precise than the timestamps from KbCheck because KbWait only checks the

keyboard every 5 ms. So typically, you shouldn’t use KbWait when timestamps are important.

Wait for a Specific Key

To wait for a specific key to be pressed, you can use a while-loop that’s only escaped when the designated key is    pressed. Let’s go through an example where you instruct the subject to “ press the spacebar to continue.” First, we   identify the key-number for the spacebar on your system; this is typically done in the setup section of your program. Don’t forget to use KbName('UnifyKeyNames') first.

keyNumSpace = min( KbName( 'space ') ) ; % key-number for 'space ' key

Now let’s prompt the user to press the spacebar (we’re assuming you’ve opened a window called w):

% prompt user (using centered, yellow text) to press the spacebar

DrawFormattedText(w, 'Press the spacebar continue', 'center', 'center', [255 255 0]) ;

Screen( 'Flip', w) ;

Now we use KbCheck or KbWait (either function will give us the keyCode vector that we need) inside a while-loop that’s only escaped when the spacebar is pressed. If timing isn’t important, we can use KbWait:

% wait for spacebar to be pressed

keyCode = zeros(1,256)       ; % initialize vector of key-statuses

while ~keyCode(keyNumSpace)    % stay in while-loop as long as spacebar is up

[~, keyCode] = KbWait(-1) ; % wait for key-press, get vector of key-statuses

end

Here we do the same thing using KbCheck, and get a timestamp for the key-press:

% wait for spacebar to be pressed

keyCode = zeros(1,256) ;                  % initialize vector of key statuses

while ~keyCode(keyNumSpace)              % stay in while-loop til spacebar pressed

[~, keySecs, keyCode] = KbCheck(-1) ; % current timestamp, vector of key-statuses

end

The above examples illustrate that the ~ symbol has two different functions. In general, the  ~ symbol is a logical

operator that means not” or is zero.” Thus, in the above code, ~keyCode(keyNumSpace) is equivalent to

keyCode(keyNumSpace)==0. But in a vector of output arguments, the ~ symbol means “skip this argument.” Thus, when we say  [~, keyCode] we’re telling Matlab to the first output argument because we don’t need it.

Wait for One of Multiple Specific Keys

This is the same idea as the previous example, but extended to allow multiple options for which key is pressed. We’re

using KbWait (in mode 2) here because timing isn’t important and because it’s convenient that KbWait mode 2 automatically waits for all keys to be up before checking for a fresh key-press. But remember, when timing is

important, use KbCheck instead.

% identify key-numbers for '1!', '2@ ', and '3#' keys in the top row on the keyboard

% (not to be confused with the '1', '2', and '3' keys, which are on the number pad)

keyNumTop1 = min( KbName('1! ') ) ; % key-number for the 1! key

keyNumTop2 = min( KbName('2@ ') ) ; % key-number for the 2@ key

keyNumTop3 = min( KbName('3# ') ) ; % key-number for the 3# key

% prompt user (using centered, magenta text) for input

DrawFormattedText(w, 'On a scale of 1 to 3, how do you feel? ', ...

'center', 'center', [255 0 255]) ;

Screen( 'Flip', w) ;

% stay in while-loop until '1!', '2@', or '3#' key is pressed

keyCode = zeros(1,256) ; % initialize vector of key statuses

while ~keyCode(keyNumTop1) && ~keyCode(keyNumTop2) && ~keyCode(keyNumTop3)

[~, keyCode] = KbWait(-1, 2) ; % after all keys are up, wait for key-press,

% get vector of key-statuses

end

Here’s an equivalent version of the while-statement in the above while-loop:

while sum( keyCode([keyNumTop1 keyNumTop2 keyNumTop3]) ) == 0

And here’s another equivalent version:

while ~sum( keyCode([keyNumTop1 keyNumTop2 keyNumTop3]) )

After the while-loop, we typically want to store the user’s response:

% record subject’s rating of how they feel today

if keyCode(keyNumTop1) == 1

feelTodayRating = 1 ;

elseif keyCode(keyNumTop2) == 1

feelTodayRating = 2 ;

else % if keyCode(keyNumTop3) == 1

feelTodayRating = 3 ;

end

Note that each == 1 is optional in the above code. For example, if we just say

if keyCode(keyNumTop1)

that means if keyCode(keyNumTop1) is a non-zero value.”

The RestrictKeysForKbCheck function

When you’re only interested in specific keys, the RestrictKeysForKbCheck function can be used to make

KbCheck even faster, by specifying in advance which keys KbCheck should pay attention to. For instance, here’s how you can detect a spacebar press very quickly (assuming you’ve defined keyNumSpace):

% wait for spacebar to be pressed

RestrictKeysForKbCheck(keyNumSpace) ; % diregard all keys except spacebar

while ~KbCheck(-1)                    % stay in while-loop until key-press detected

end

And here’s how you can get a very precise timestamp for the  '1!',  '2@', or  '3#' key being pressed (assuming you’ve defined keyNumTop1, keyNumTop2, and keyNumTop3):

% make KbCheck ignore all keys except '1! ', '2@ ', and '3# '

RestrictKeysForKbCheck([keyNumTop1 keyNumTop2 keyNumTop3]) ;

% wait for '1! ', '2@ ', or '3# ' to be pressed

anyKeyDown = 0 ; % initialize flag indicating whether any target key is down

while ~anyKeyDown

[anyKeyDown, keySecs, keyCode] = KbCheck(-1) ; % key-statuses, keypress timestamp

end

Even if we don’t need a fast response or a precise timestamp, we might want to use the RestrictKeysForKbCheck function to make our code more efficient by eliminating the need for a while-loop. For instance, here’s how we can wait for a specific key to be pressed with KbWait without using a while-loop:

% wait for spacebar to be pressed

RestrictKeysForKbCheck(keyNumSpace) ; % disregard all keys except spacebar

KbWait(-1)                           ; % wait for key-press

A drawback of the RestrictKeysForKbCheck function is that it may prevent CTRL-C from allowing you to break out of a stuck program.

Note that KbWait uses KbCheck “under the hood,” and thus will be affected by RestrictKeysForKbCheck just as KbCheck is. Other functions that use keyboard input, such as GetEchoString (which is covered in the Part 4

handout) may use KbCheck under the hood also, depending on your system and on the input arguments.

To reset to the default behavior of paying attention to all keys (e.g., at the end of your program), just input an empty vector to the RestrictKeysForKbCheck function:

RestrictKeysForKbCheck([]) ; % stop disregarding keys

Special Considerations for Certain Systems

.     In rare cases, using KbCheck and KbWait to check for any key doesn’t work correctly, because your system is     always signaling that some weirdly named key is down, even when no key is actually down. That can happen, for  example, on certain laptops on which the keyboard is constantly sending a signal to tell the system that the laptop is open, to keep the computer from going to sleep. In such cases, you can use KbCheck to identify the key-

number of the “stuck” key, and then input that key-number to the DisableKeysForKbCheck function to tell

KbCheck and KbWait to ignore that key (or if there are multiple stuck keys, input a vector containing the key-

numbers for all the stuck keys). Of course, if you’re using the RestrictKeysForKbCheck function, this won’t be an issue, because you’ll be disregarding all the keys you’re not interested in (including stuck keys) anyway.

.    KbCheck may not detect certain keys in the usual way. For instance, on some systems, caps-lock key presses   can’t be detected. On some systems, the left shift key is detected as 2 keys ('LeftShift' and 'Shift'), as is the right shift key ('RightShift' and 'Shift'). And on most systems, only one arrow key press can be detected at a time.

.    On some Mac operating systems, KbCheck and KbWait (and other Psychtoolbox commands that check for

keyboard input) might not recognize your keystrokes at all and may even cause an error. In that case, you may

need to give Matlab permission to monitor the keyboard input, using the following steps:

1.   Quit MATLAB.

2.   Make sure your operating system is up to date (you can see your version by clicking on the Apple icon in the top-left corner of the screen and then clicking on "About This Mac").

3.   Click on the "System Preferences" or System Settings” (whichever it’s called on your system) icon on your desktop.

4.   Click on "Security & Privacy" or Privacy & Security (whichever its called on your system).

5.   In the "Privacy" menu, click on "Input Monitoring."

6.   In the list of applications that comes up, find Matlab and look to see if its checked/turned-on.

.     If permission for Matlab is checked/turned-on, turn it off; or if you have a recent operating system, remove Matlab from the list entirely by clicking on it and then clicking the minus-sign. Then close

"System Preferences" or “System Settings” (whichever it’s called on your system). Then start over from Step 4.

.     If permission for Matlab isn't checked/turned-on, turn it on; or if you have a recent operating

system, remove the application from the list entirely by clicking on it and then clicking the minus-sign, then re-add Matlab to the list by clicking the plus-sign and selecting Matlab from the directory that

comes up. Then close "System Preferences" or “System Settings” (whichever it’s called on your system), and restart Matlab.

.     If you have a recent operating system and you don’t see Matlab in the list at all, click the plus-sign and select Matlab from the directory that comes up to give Matlab permission. Then close "System

Preferences" or “System Settings” (whichever it’s called on your system), and restart Matlab.