Home Articles Books Downloads FAQs Tips

Q: Send keystrokes to a control or window


Answer

The 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 function

The 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 code

The 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_event

The 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.


Notes

Note: 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.


Downloads for this FAQ
sendkey.zip BCB3 project that demonstrates how to use keybd_event to simulate keystrokes.
sendkeyx.zip Same as sendkey.zip. Includes an EXE. Download is 138 k.


Copyright © 1997-2000 by Harold Howe.
All rights reserved.