Playing with the Keyboard
There are times when you want to test if a key is pressed at a given time without having to wait for a KeyDown event, specially if the code is not executing from a control or window that has a Keydown event. In REALBasic you can use the function AsyncKeyDown of the intrinsic object KEYBOARD to check the status of a key asynchronous at any time.
Before we talk about using the function Keyboard.AsyncKeyDown we need to understand how keyboards work. Not all Keyboard have the same layout. For example a spanish or german keyboard have additional letters and actual keys are arranged differently on the keyboard. Keyboards also come in different shapes and flavors from 84 keys, 10 function keys, 12 function keys, 101 keys etc, some have extra keys for things like email, web browsing, control the volume of the computer, etc. When you press a key on a keyboard it actually sends a "scan code" to the Operating Systems which is then responsible to translate the scan code into a character or control key given the current settings of the machine. This true for Mac and PC hardware. To ease the differences among keyboards the Operating Systems maps scan codes to a Virtual Key Codes.
Every physical key on the keyboard has an unique Virtual Keycode. Notice that a Virtual Keycode is NOT a code for the actual symbol labeled on top of the key, it is just a code to identify that a particular key was pressed. For example the number "three" on the top row of traditional keyboards has a different Virtual Keycode than the "three" on the numeric keypad. For this same reason the Virtual Keycode for the character "M" and the character "m" will be the same because they are both the same physical key. There is a catch in Mac. In Mac OS some physical keys actually generate the same Virtual Keycode regardless of their location. This is true for the Shift, Control, Option and Command keys.
In Mac OS a key map is used to convert a key code to a virtual key code. The system software then uses a script specific keyboard layout to map a virtual keycode to a character. A system may have a script map for french, english etc. The Script Manager is the part of the MacOS Toolbox (the equivalent to Windows API) coordinates the interaction between many parts of the Mac OS and those available script systems. While a script (Toolbox lingo) is a collection of resources that provides for the representation of a particular writing system. (All that from a quick copy-paste of Script Manager Reference) Notice that the Script Manager while still supported in CoreServices is now more of a legacy and devolopers are encourage to use the Unicodce services instead.
In Mac OS X we use Keyboard Layouts instead of old KCHR resources when mapping a Virtual Keycode to an actual character. Keyboards Layout are XML based files and are found at: "/System/Library/Keyboard\ Layouts/Unicode.bundle/Contents/Resources/". If you are an avid Linux user you will find that Apple's keyboard layouts are quite similar to Linux's kemaps files. In OS X we use UCKeyTranslate to convert a Virtual Keycode to the equivalent character representation in unicode. A UCKeyTranslate is similar to the now deprecated KeyTranslate used with the Script Manager and KCHR resources. The value returned by UCKeyTranslate will depend on the currently selected keyboard layout, status of shift key and other control keys. Using the Carbon Event Manager in MacOS you can inspect the message part of the Keydown event using the constant keyCodeMask $0000FF00 as a mask to obtain the actual virtual key code.
For windows you can find the Virtual Key Codes here. You can use the windows API function MapVirtualKey() to convert from a virtual key code to a scan code, from a scan code to a Virtual key code, or from a Virtual keycode to a character. You can check actual scan codes for PC's according to Windows Hardware Quality Labs here. In Windows using US Extended keyboard ASCII charaters match thier Virtual Keycode which is an added bonus.
In Unix systems similar functionality is provided into layers. First the Kernel translates scan codes into Virtual keycodes using the loaded keymap. In X11 environments X offers its own functionality to map keys. When X will use the Kernels keymap as base of its own key mapping functionality. Applications running under an X server use keysym instead of keycodes. A keysym is the actual charater after it is translated using X keyboard mappings. A keysym is similar to the functionality achieved by the functions UCKeyTranslate and MapVirtualKey in the other OSes. In Linux use showkey to display a key's keycode. The command line utility getkeycodes will display the conversion table used to map scan codes to keycodes. In "/usr/include/linux/input.h" we can find the symbolic names for the keycodes. An easier way is to run X and in an X terminal run the command "xev". Now press a key on your keyboard and note the generated keycode.
I have include an image of Apples Virtual Key Codes here:
The function Keyboard.AsyncKeyDown takes an integer that represents the keycode of a particular key and returns True if the key is pressed else it returns false. In REALBasic a keycode is not an actual scan code but a Virtual Key Code. Notice that Visual Basic's keycodes are also Virtual Key Codes.
Now that we now how to find out which key code represents which key we can use Keyboard.AsyncKeyDown to test for a particular key. Lets see the following example:
If Keyboard.AsyncKeyDown(123) then
The above example test is the Left arrow key is pressed in MacOS. If you have compared the virtual codes of MacOS and Windows you know that they are different. To solve this problem you can code the test as:
#if targetMacOS then
If Keyboard.AsyncKeyDown(kLeftKey) then
You could also add a constant to a module instead of using the pragma statement in code. If you know what keys you need this approach good enough, yet if you want to support all the keys or a large number of keys this may not be good solution. In issue 3.2 of the REALBasic Developer Magazine Lars Jensen published a great article in a cross-platform solution for handling asynchronous keys.
Here is a table with some keycodes for the three platforms. It is based on a US Extended keyboard layout.
I put together a REALbasic module with Keycode constants for Linux and Windows. Notice Windows contants are the same as in VB 6. Download module in XML.
David Pogue’s comparison of keyboard shortcuts on Windows and on the Mac.
December 1, 2006