Products | Support | Solutions | CodeDev | About  

ARTICLES: The Keyboard

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
msgbox "Left key pressed"
end if

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
    const kLeftKey = 123
#elseif targetWin32 then
    const kLeftKey = 37
#elseif targetLinux then
    const kLeftKey = 105

If Keyboard.AsyncKeyDown(kLeftKey) then
    msgbox "Left key pressed"
end if

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.

Key Mac Windows Linux Notes
rbKeyUp 126 26 103
rbKeyDown 125 28 108
rbKeyLeft 123 25 105
rbKeyRight 124 27 106
rbKeyBackspace 117 8 14
rbKeyEnter 76 * 28
rbKeyHome 115 36 102
rbKeyEnd 119 35 107
rbKeyPageDown 121 34 109
rbKeyPageUp 116 33 104
rbKeyReturn 36 13 *
rbKeyDelete 51 46 111
rbKeyTab 48 9 15
rbKeySpacebar 49 20 57
rbKeyShift 56 10 *
rbKeyControl 59 11 *
rbKeyMenu 58 18 139 The Alt key
rbKeyPrintScreen * 42 210
rbKeyEscape 53 27 1
rbKeyCapsLock 57 20 58
rbKeyHelp 114 47 138
rbKeyF1 122 112 59
rbKeyF2 120 113 60
rbKeyF3 99 114 61
rbKeyF4 118 115 62
rbKeyF5 96 116 63
rbKeyF6 97 117 64
rbKeyF7 98 118 65
rbKeyF8 100 119 66
rbKeyF9 101 120 67
rbKeyF10 109 121 68
rbKeyF11 103 122 87
rbKeyF12 111 123 88
rbKeyMacFn 63 * *
rbKeyMacOption 58 * *
rbKeyMacCommand 55 * *
rbKeyWinLeftWindow * 91 * On "Natural" keyboards
rbKeyWinRightWindow * 92 * On "Natural" keyboards
rbKeyWinApplication 110 93 * On "Natural" keyboards
rbKeyQ 12 81 16
rbKeyW 13 87 17
rbKeyE 14 69 18
rbKeyR 15 82 19
rbKeyT 17 84 20
rbKeyY 16 89 21
rbKeyU 32 85 22
rbKeyI 34 73 23
rbKeyO 31 79 24
rbKeyP 35 80 25
rbKeyA * 65 30
rbKeyS 1 83 31
rbKeyD 2 68 32
rbKeyF 3 70 33
rbKeyG 5 71 34
rbKeyH 4 72 35
rbKeyJ 38 74 36
rbKeyK 40 75 37
rbKeyL 37 76 38
rbKeyZ 6 90 44
rbKeyX 7 88 45
rbKeyC 8 67 46
rbKeyV 9 86 47
rbKeyB 11 66 48
rbKeyN 45 78 49
rbKeyM 46 77 50
rbKey0 29 48 11
rbKey1 18 49 2
rbKey2 19 50 3
rbKey3 20 51 4
rbKey4 21 52 5
rbKey5 23 53 6
rbKey6 22 54 7
rbKey7 26 55 8
rbKey8 28 56 9
rbKey9 25 57 10
rbKeyPeriod 47 190 52
rbKeyComma 43 188 51
rbKeySlash 44 191 53 The key with /? generally next to right shift key.
rbKeyNum0 82 96 82 On numeric keypad or with NumLock
rbKeyNum1 83 97 79 On numeric keypad or with NumLock
rbKeyNum2 84 98 80 On numeric keypad or with NumLock
rbKeyNum3 85 99 81 On numeric keypad or with NumLock
rbKeyNum4 86 100 75 On numeric keypad or with NumLock
rbKeyNum5 87 101 76 On numeric keypad or with NumLock
rbKeyNum6 88 102 77 On numeric keypad or with NumLock
rbKeyNum7 89 103 71 On numeric keypad or with NumLock
rbKeyNum8 91 104 72 On numeric keypad or with NumLock
rbKeyNum9 92 105 73 On numeric keypad or with NumLock
rbKeyMultiply 67 106 55 On numeric keypad or with NumLock
rbKeyAdd 69 107 78 On numeric keypad or with NumLock
rbKeySubtract 78 109 74 On numeric keypad or with NumLock
rbKeyDivide 75 111 98 On numeric keypad or with NumLock
rbKeyDecimal 65 110 83 On numeric keypad or with NumLock
rbKeyNumEqual 81 * 117 On numeric keypad or with NumLock

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.

Related Links:

David Pogue’s comparison of keyboard shortcuts on Windows and on the Mac.
Customizing the Cocoa Text System by Jacob Rus. View.
Cocoa Keyboard Interface Control. View.
Consistent keyboard configurations in Linux by John Bunch. View.

December 1, 2006
Jose L. Cuevas

User Contributed Notes   Add Note
Posted by: jose(@)
3/7/2005, 22:50:09
Does anybody has a module with keycode constants?

It would be a great addition to this article.