![]() |
![]() |
|||||||||||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
|||||||
Q: Send keystrokes to a control or windowAnswerThe API function keybd_event allows you to synthesize a keyboard event. This is the same function that the keyboard driver uses to tell the OS that the user is pressing or releasing a key. The keyboard messages will be sent to the control or window that currently has the input focus. To simulate a key press, you call keybd_event once to simulate the user pressing a key, and then you call keybd_event a second time to signal that the key was released. Understanding the keybd_event functionThe prototype for keybd_event looks like this: VOID keybd_event( BYTE bVk, // virtual-key code BYTE bScan, // hardware scan code DWORD dwFlags, // options flag DWORD dwExtraInfo // additional data ); The first argument is the virtual key code for the key that you want to simulate. Possible values include VK_RETURN, VK_NUMPAD0, VK_F1, and the ASCII codes for the upper case alpha keys and the numeric keys. For a complete list of virtual key codes, look in the API include file WINUSER.H, or look in the microsoft API help file win32.hlp under the index Virtual-Key Codes. The second argument to keybd_event specifies the hardware scan code of the key. You can usually set this value to 0 when you specify the virtual key code in the first argument. Hardware scan codes are OEM dependent, and the only way to reliably obtain one is to pass a virtual key code to the MapVirtualKey API funtion. The dwFlags argument is a bit flag that be can contain any or none of the following values. KEYEVENTF_EXTENDEDKEY KEYEVENTF_KEYUP The first flag works in conjunction with the scan code, so you won't use it very often. The KEYEVENTF_KEYUP flag tells the OS that the key is being released. The dwExtraInfo parameter is a utility argument that is rarely used. Sample codeThe examples below demonstrate how to use keybd_event to simulate a variety of keystrokes. void __fastcall TForm1::Button1Click(TObject *Sender) { // This function simulates the press of a lower case 'a' // The key will be 'a' and not 'A' because we don't // simulate a press of the shift key. Note that we // must pass upper case letters to keybd_event. // Note: if you hold down the shift key while testing this code // an uppercase 'A' will appear in the edit box // Focus the edit control so it receives the key event Edit1->SetFocus(); // Simulate the user pressing the A on the keyboard keybd_event('A', 0,0,0); // Simulate the user releasing the the A on the keyboard keybd_event('A', 0,KEYEVENTF_KEYUP,0); } void __fastcall TForm1::Button2Click(TObject *Sender) { // The previous function put an 'a' in the edit box if the code // happened to run while the user was not holding the shift key or had // the caps lock on. This code ensures that a lower case 'a' is sent, even // if the user is holding down the ctrl key, alt key, the shift key, etc // Find out which of the special keys are down bool bCtrlDown = GetKeyState (VK_CONTROL) & 0x8000; bool bAltDown = GetKeyState (VK_MENU) & 0x8000; bool bShiftDown = GetKeyState (VK_SHIFT) & 0x8000; bool bLWindowsDown = GetKeyState (VK_LWIN) & 0x8000; bool bRWindowsDown = GetKeyState (VK_RWIN) & 0x8000; bool bAppsDown = GetKeyState (VK_APPS) & 0x8000; bool bCapsOn = GetKeyState (VK_CAPITAL) & 0x0001; // For each special key that was down, simulate that the // user has let go of the key if(bCtrlDown) keybd_event(VK_CONTROL, 0,KEYEVENTF_KEYUP,0); if(bAltDown) keybd_event(VK_MENU, 0,KEYEVENTF_KEYUP,0); if(bShiftDown) keybd_event(VK_SHIFT, 0,KEYEVENTF_KEYUP,0); if(bLWindowsDown) keybd_event(VK_LWIN, 0,KEYEVENTF_KEYUP,0); if(bRWindowsDown) keybd_event(VK_RWIN, 0,KEYEVENTF_KEYUP,0); if(bAppsDown) keybd_event(VK_APPS, 0,KEYEVENTF_KEYUP,0); if(bCapsOn) { // If caps lock is on, we need to press the caps lock // and then let go of it to turn it off keybd_event(VK_CAPITAL, 0, 0 ,0); keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP,0); } // At this point, we know that caps lock is off, and the // shift, ctrl, alt, and other keys have been released // Focus the edit control so it receives the key event Edit1->SetFocus(); // Simulate the user pressing the A on the keyboard keybd_event('A', 0,0,0); // Simulate the user releasing the the A on the keyboard keybd_event('A', 0,KEYEVENTF_KEYUP,0); // now return the shift, ctrl, capslock, etc to their original state if(bCtrlDown) keybd_event(VK_CONTROL, 0,0,0); if(bAltDown) keybd_event(VK_MENU, 0,0,0); if(bShiftDown) keybd_event(VK_SHIFT, 0,0,0); if(bLWindowsDown) keybd_event(VK_LWIN, 0,0,0); if(bRWindowsDown) keybd_event(VK_RWIN, 0,0,0); if(bAppsDown) keybd_event(VK_APPS, 0,0,0); if(bCapsOn) { keybd_event(VK_CAPITAL, 0, 0 ,0); keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP,0); } } void __fastcall TForm1::Button3Click(TObject *Sender) { // This function toggles the state of the caps lock keybd_event(VK_CAPITAL, 0, 0 ,0); keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP,0); } void __fastcall TForm1::Button4Click(TObject *Sender) { // This function performs a screen capture of the active // window by simulating a press of the print screen key keybd_event(VK_SNAPSHOT, 0, 0 ,0); keybd_event(VK_SNAPSHOT, 0, KEYEVENTF_KEYUP,0); } void __fastcall TForm1::Button5Click(TObject *Sender) { // This function captures the entire screen to the clipboard keybd_event(VK_SNAPSHOT, 1, 0 ,0); keybd_event(VK_SNAPSHOT, 1, KEYEVENTF_KEYUP,0); } void __fastcall TForm1::Button6Click(TObject *Sender) { // Here is a cheesy way to tab to the next process by // simulating an ALT-TAB event. keybd_event(VK_MENU, 0, 0 ,0); keybd_event(VK_TAB, 0, 0 ,0); keybd_event(VK_TAB, 0, KEYEVENTF_KEYUP,0); keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP,0); } void __fastcall TForm1::Button7Click(TObject *Sender) { // This code simulates the Windows + M hotkey for // minimizing all open windows. keybd_event(VK_LWIN, 0, 0 ,0); keybd_event('M', 0, 0 ,0); keybd_event('M', 0, KEYEVENTF_KEYUP,0); keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP,0); } Encapsulating keybd_eventThe keybd_event API function isn't too difficult to understand. However, it might be a good idea to add a wrapper to keybd_event. There are several reasons you might want to do this. For starters, keybd_event looks sort of cryptic, so you might not want to litter your code with keybd_event calls. Secondly, you can really mess up the system if you depress a key, and then forget to release it when you are done. Encapsulating keybd_event can help prevent this from happening. The Delphi developer support page at the Inprise website contains an FAQ for simulating keystrokes. NotesNote: Due to a limitation in the OS, you cannot use the keybd_event function to toggle the num lock key on a machine that runs Windows 95. It will work on Windows NT.
| ||||||||||||
All rights reserved. |