Jump to content
xisto Community
Sign in to follow this  
mitchellmckain

Handling Keyboard Input In Win32 virtal key codes and scan codes

Recommended Posts

(Personal note: I am a physics teacher and a hobby programmer. Since I doubt anyone here is interested in a physics tutorial I figured it would be better to write a tutorial on something I learned while programming.) What I will cover here may be considered something of a lost art since keyboard control has been largely replaced by the use of the mouse. A lot of users are bewildered by the keyboard and the effort of deciding which one to push. Therefore, point and click has come to be considered a superior method of program control. Most programmers only deal with keyboard input after some windows procedure like getch is through with it and all you see is an ascii code. They might not realize that this ascii code has very little to do with the keyboard in front of them. In a Win32 program you handle messages that originate from the keyboard, and all the information from the original keyboard event can be recovered. Programming in Win32 is a messy subject and a lot of it is best side-stepped by modifying a previous program and learning as you go along. In any case, there are a lot of great Win32 tutorials out there already. Since this material is based on Win32 I will point out a few here, but all are found easily with Google. http://www.functionx.com/win32/http://www.winprog.org/tutorial/ members.net-tech.com.au/alaneb/win32.html http://forums.xisto.com/no_longer_exists/ http://www.catch22.net/tuts/ The basic win32 program calls a proceedure to set up the window then goes into an endless loop which checks for messages (caused by user input) and updates the display. The messages are handled by a callback proceedure (sometimes called WndProc), written by you, but which is called by the operating system. This WndProc gets four parameters but only three important parameters: a message identifier and two words of data often refered to as wParam and lParam though we could call them data1 and data2. Your WndProc usually consist of nested switch statements in order to respond to the various messages according to the identifier and data sent to it. There are constants defined in windows.h like WM_CREATE and WM_COMMAND for different message identifiers that aid you in constructing this switch statement. For example, WM_CREATE message is sent when the window is created so you can use procedures like AppendMenu and SetMenu to create a window menu bar. The WM_COMMAND message is sent when a window menu item has been selected and the data1 pararameter tells you which one is selected. When you handle the message you return a 0 back the caller, otherwise pass the parameters on to the default windows message handler, DefWindowProc. For example,


 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM data1, LPARAM data2) {    switch(uMsg) {[tab][/tab]case WM_CREATE: <code to create menus>   return 0;[tab][/tab]case WM_COMMAND:   switch(data1) {            case ID_HELP_ABOUT: <code to display "About this File" message>  return 0;     <other cases to handle menu selections>     }[tab][/tab]}    // Pass all unhandled messages to DefWindowProc    return DefWindowProc(hWnd,uMsg,wParam,lParam);    }

For this tutorial, the message identifiers we are interested in are: WM_KEYUP, WM_SYSKEYUP, WM_KEYDOWN, and WM_SYSKEYDOWN. These are sent whenever a keyboard key is pushed or released. All the information, about what key was pressed and how, is contained in data1 and data2. Data1 contains something called the virtual keycode. This is a code halfway translated to ascii that is sufficient for the keyboard control of many applications. For example all the letter keys have a virtual key code that is just the ascii code for the capital letters and the number keys above the letters have a virtual key code that is ascii codes for these digits. But, the numeric keypad numbers, for example, have different virtual key codes 96-105 to distinguish them from the other keys. However, the virtual keycode alone does not uniquely identify every key on todays enhanced keyboards, therefore data2 is useful in recovering this information. Data2 is a composite of different numbers and bits. The lower 16 bits (0 thru 15) is an auto repeat count. When a key is held down, depending on the windows settings, it is interpreted as repeated a number of times corresponding to how long the key was held down. If the key is held down long enough, more KEYDOWN messages are sent with repeat counts for the additional time they key is held down. Bit 30 is set in this case to indicate that these are additional KEYDOWN messages and that the key was already down. Bits 16 through 23 contain a more primitive keyboard code called the scan code. The scan code is closely related to the actual position of the keyboard buttons on the keyboard (so it is keyboard dependent), but it doesn't distinguish the keypad and many other keys on todays keyboards. On my keyboard for example, the numeric keys 1 through 9 and 0 have scan codes 2 through 11. The numbers on the key pad, and any other arrow keys, insert, delete, home, end, pgup, and pgdn all have the same scan codes 2 through 11. Bit 24 is set for the extended keys on todays extended keyboards. These include the right hand alt and ctrl keys, the arrow keys and the insert, delete, home, end, pgup, and pgdn keys, as well as the enter, / and numlock keys on the keypad. This helps distinguish a lot of keys that have the same scan codes or virtual key codes. Bit 29 is set if the alt key is being held down. Bit 31 is 1 for key up messages and 0 for key down messages. Bits 25 to 28 are not used. |_key_|already|alt key_|_not used_|extend_|_scan code_|_repeat count_| |_up__|_down_|_down_|(reserved) |_key__|__________ |____________| |__31_|__30__|__29___|_25-28___|__24__|__16-23____|___0-15_____| So for example, the repeat count is given by (data2 & 65535) and the scan code is is given by ((data>>16) & 255). Ok, now for programming. You usually want to keep track of what keys are up and what keys are down, especially the shift and ctrl keys. As for the alt key you can either keep track of its status yourself or use bit 29 in data2. I use both. The first for programming parallelism and the second to double check it. A 255 length boolean array using the virtual key code as the index is a standard way of keeping track of which keys are up and which are down. Clearing this array is all you usually want to do for WM_KEYUP, WM_SYSKEYUP. For WM_KEYDOWN and WM_SYSKEYDOWN, you need to test for the shift button (data1 == 16), the ctrl button (data1 == 17) and the alt button (data1 == 18) to update your boolean array and usually nothing else. For example,


 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM data1, LPARAM data2) {    switch(uMsg) {[tab][/tab]case WM_CREATE: <code to create menus>   return 0;[tab][/tab]case WM_COMMAND: <code to handle menu selections>   return 0;[tab][/tab]case WM_SYSKEYUP:[tab][/tab]case WM_KEYUP:   keys[data1]=false;   return 0;[tab][/tab]case WM_SYSKEYDOWN:[tab][/tab]case WM_KEYDOWN:   if(data1>16 && data1<18){keys[data1]=true;return 0;}   switch(data1){     <code to handle other keypresses>     }[tab][/tab][tab][/tab]}    // Pass all unhandled messages to DefWindowProc    return DefWindowProc(hWnd,uMsg,wParam,lParam);    }

Although it makes sense to keep track of whether the shift, ctrl and alt keys are up or down, you cannot trust your determination in a winodowed program. The reason is that your program will only receive a key up message if your program is the currently selected window (in focus as they say). Therefore it is a good idea to verify the status of these buttons every few seconds or so with something like GetKeyState, for example. You pass the virtual key code to GetKeyState and it returns a nonzero integer if the key is down, unless it is a toggle key like caplock (in which case it returns 1 if the key is toggled but not down).


Edited by OpaQue (see edit history)

Share this post


Link to post
Share on other sites

By the way I forgot to mention the difference between the SYSKEY messages and the KEY messages. A SYSKEY message is sent if the alt button is being held down or supposedly if no program is in focus when the key is pressed. I have never experienced this second case so I cannot vouch for it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

Terms of Use | Privacy Policy | Guidelines | We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.