Click here to Skip to main content
15,888,802 members
Articles / Desktop Programming / MFC
Article

Onscreen Keyboard

Rate me:
Please Sign up or sign in to vote.
4.71/5 (34 votes)
21 Mar 2000 666.7K   16.9K   102   92
An onscreen keyboard for pen computing and touchscreens
  • Download source files - 143 Kb

    Sample Image - OnscreenKeyboard.gif

    I needed a simple onscreen keyboard to interface with a touch / pen based computer that I bought through an online auction. Although Microsoft supplies one with its Pen Extensions 2.0 it only works win Win95 and I wanted to use NT.

    All of the available onscreen keyboards I found were either too expensive, or they were only designed to operate with 3.1 and 9x so (of course) I decided to see if I could make one. Along the way I learned a little about how the keyboard is handled, and the thread keyboard maps.

    Included with this article is a working, but simple, onscreen keyboard. I submitted it mostly as an example of the methods:

    • AttachThreadInput
    • keybd_event
    • VkKeyScan
    • GetKeyState

    This program has one nasty limitation, and that is that it "flashes" since it does not prevent the changing of focus to itself when clicked, and then back to the target window when the keystroke is generated. If someone wants to tackle that one please feel free ;-)

  • License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here


    Written By
    United States United States
    This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

    Comments and Discussions

     
    GeneralRe: Doesn't work with IE Pin
    Thomas Righetti28-Jun-04 21:43
    Thomas Righetti28-Jun-04 21:43 
    GeneralRe: Doesn't work with IE Pin
    Dirk Moshage17-Aug-04 1:36
    Dirk Moshage17-Aug-04 1:36 
    GeneralRe: Doesn't work with IE Pin
    Ole Martin Brynildsen2-Sep-04 4:16
    Ole Martin Brynildsen2-Sep-04 4:16 
    GeneralRe: Doesn't work with IE Pin
    CoreyCooper29-Jun-04 6:14
    CoreyCooper29-Jun-04 6:14 
    GeneralGreat!!! Pin
    17-Sep-01 18:57
    suss17-Sep-01 18:57 
    GeneralA Problem about the keyboard Pin
    Ray31-Oct-00 6:28
    Ray31-Oct-00 6:28 
    GeneralRe: A Problem about the keyboard Pin
    17-Mar-01 5:33
    suss17-Mar-01 5:33 
    GeneralRe: A Problem about the keyboard Pin
    25-Oct-01 4:56
    suss25-Oct-01 4:56 
    An alternative to the implementation in this example that used the Keybd_event function may be the SendInput function:

    UINT SendInput(
    UINT nInputs, // count of input events
    LPINPUT pInputs, // array of input events to insert
    int cbSize // size of an INPUT structure
    );

    I like SendInput for simulating Key events since I can stuff the queue in the order I want and just get away with virtual key codes. For example, If I use SendInput to stuff the Keyboard input buffer with the following order of events:

    KEY_DOWN event for 0x10 // virtual key code for shift,
    KEY_DOWN event for 0x31 // Virtual key code for 0,
    KEY_UP event for 0x10
    KEY_UP event for 0x31

    I end up with the "!" placed in the window with the current focus (and there was much rejoicing). I like this approach a bit better since it maps to the way we humans would enter it on the keyboard and I avoid any higher level thought process, bit twiddling, etc. SendInput uses the INPUT struct which contains a union to structs for keyboard events (ki), mouse events (mi) and hardware events (hi). Hopefully, the hastily typed out code fragment that I am including for my discussion isn't too badly reasoned (long day and brain like mush ...). This fragment assumes you have done the proper prerequisite work to get your environment set up not to choke on SendInput, the associated INPUT struct, and the ki struct ... and hopefully gives you an idea of implementing SendInput versus Keybd_event:


    // Purpose: SendKey - Sends key events to the window with the current
    // focus.
    // Uses: SendInput Declared in winuser.h; Import Library: user32.lib.
    // Compatibility: NT 4.0(SP3)or later;Win 98 or later;CE Unsupported
    // Args:
    // vk = Virtual Keycode for simulated key event,
    // shift = vk code for shift or pass 0 if shift is not simulated
    // control = vk code for control or pass 0 in no control
    // alt = you guessed it ... vk code for alt or pass 0

    void Sendkey(int vk, int shift, int control, int alt);

    void SendKey(int vk, int shift, int control, int alt)
    {

    // special key ... the vk code holder for shift,control,or alt.

    int spkey;

    // A key is either shifted, control or alt. Determine which and
    // build the keybuffer to accept to keys for this event.

    if (shift || control || alt)
    {
    if (shift) spkey = shift;
    else if (control) spkey = control;
    else spkey = alt;

    INPUT *buffer = new INPUT[4]; //allocate a buffer
    buffer->type = INPUT_KEYBOARD;
    buffer->ki.wVk = spkey;
    buffer->ki.wScan = 0;
    buffer->ki.time = 0;
    buffer->ki.dwFlags = 0;
    buffer->ki.dwExtraInfo =0;

    (buffer+1)->type = INPUT_KEYBOARD;
    (buffer+1)->ki.wVk = vk;
    (buffer+1)->ki.wScan = 0;
    (buffer+1)->ki.time = 0;
    (buffer+1)->ki.dwFlags = 0;
    (buffer+1)->ki.dwExtraInfo =0;

    (buffer+2)->type = INPUT_KEYBOARD;
    (buffer+2)->ki.wVk = spkey;
    (buffer+2)->ki.wScan = 0;
    (buffer+2)->ki.time = 0;
    (buffer+2)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+2)->ki.dwExtraInfo = 0;

    (buffer+3)->type = INPUT_KEYBOARD;
    (buffer+3)->ki.wVk = vk;
    (buffer+3)->ki.wScan = 0;
    (buffer+3)->ki.time = 0;
    (buffer+3)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+3)->ki.dwExtraInfo = 0;

    // Here is the Sendinput function implemented
    // queue is stuffed with 4 events pointed to by buffer
    // with the sizeof an INPUT struct.

    SendInput(4,buffer,sizeof(INPUT));
    delete (buffer); // We always clean up our messes.
    }

    // Check for combinations of 2 special keys, i.e. shift-alt,
    // ctrl-alt,shift-ctrl by intersecting logical conditions of
    // the 3 possible keys that can be pressed at once and building
    // the buffer to accept 3 key events.

    else if ((shift || control) && (control || alt))
    {

    INPUT *buffer = new INPUT[6]; //Buffer 3 key events

    // Key Presses .. the first 3 events what are the 2 keys modifying
    // the third?

    // Determine first condition for which key had a value ...
    // either shift or control and input the key into the buffer.

    if (shift) spkey = shift;
    else spkey = control;

    buffer->type = INPUT_KEYBOARD;
    buffer->ki.wVk = spkey;
    buffer->ki.wScan = 0;
    buffer->ki.time = 0;
    buffer->ki.dwFlags = 0;
    buffer->ki.dwExtraInfo =0;

    // Determine what the second key is that made the test true
    // and put the key into the buffer.

    if (alt) spkey = alt;
    else spkey = control;

    (buffer+1)->type = INPUT_KEYBOARD;
    (buffer+1)->ki.wVk = spkey;
    (buffer+1)->ki.wScan = 0;
    (buffer+1)->ki.time = 0;
    (buffer+1)->ki.dwFlags = 0;
    (buffer+1)->ki.dwExtraInfo =0;

    (buffer+2)->type = INPUT_KEYBOARD;
    (buffer+2)->ki.wVk = vk;
    (buffer+2)->ki.wScan = 0;
    (buffer+2)->ki.time = 0;
    (buffer+2)->ki.dwFlags = 0;
    (buffer+2)->ki.dwExtraInfo = 0;

    (buffer+3)->type = INPUT_KEYBOARD;
    (buffer+3)->ki.wVk = buffer->ki.wVk;
    (buffer+3)->ki.wScan = 0;
    (buffer+3)->ki.time = 0;
    (buffer+3)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+3)->ki.dwExtraInfo = 0;

    (buffer+4)->type = INPUT_KEYBOARD;
    (buffer+4)->ki.wVk = (buffer+1)->ki.wVk;
    (buffer+4)->ki.wScan = 0;
    (buffer+4)->ki.time = 0;
    (buffer+4)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+4)->ki.dwExtraInfo = 0;

    (buffer+5)->type = INPUT_KEYBOARD;
    (buffer+5)->ki.wVk = vk;
    (buffer+5)->ki.wScan = 0;
    (buffer+5)->ki.time = 0;
    (buffer+5)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+5)->ki.dwExtraInfo = 0;

    SendInput(6,buffer,sizeof(INPUT));
    delete(buffer);
    }

    // the dreaded Shift, Control, Alt + Key combination

    else if (shift && control && alt)
    {

    INPUT *buffer = new INPUT[8];

    buffer->type = INPUT_KEYBOARD;
    buffer->ki.wVk = shift;
    buffer->ki.wScan = 0;
    buffer->ki.time = 0;
    buffer->ki.dwFlags = 0;
    buffer->ki.dwExtraInfo =0;

    (buffer+1)->type = INPUT_KEYBOARD;
    (buffer+1)->ki.wVk = control;
    (buffer+1)->ki.wScan = 0;
    (buffer+1)->ki.time = 0;
    (buffer+1)->ki.dwFlags = 0;
    (buffer+1)->ki.dwExtraInfo =0;

    (buffer+2)->type = INPUT_KEYBOARD;
    (buffer+2)->ki.wVk = alt;
    (buffer+2)->ki.wScan = 0;
    (buffer+2)->ki.time = 0;
    (buffer+2)->ki.dwFlags = 0;
    (buffer+2)->ki.dwExtraInfo = 0;

    (buffer+3)->type = INPUT_KEYBOARD;
    (buffer+3)->ki.wVk = vk;
    (buffer+3)->ki.wScan = 0;
    (buffer+3)->ki.time = 0;
    (buffer+3)->ki.dwFlags = 0;
    (buffer+3)->ki.dwExtraInfo = 0;

    (buffer+4)->type = INPUT_KEYBOARD;
    (buffer+4)->ki.wVk = shift;
    (buffer+4)->ki.wScan = 0;
    (buffer+4)->ki.time = 0;
    (buffer+4)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+4)->ki.dwExtraInfo = 0;

    (buffer+5)->type = INPUT_KEYBOARD;
    (buffer+5)->ki.wVk = control;
    (buffer+5)->ki.wScan = 0;
    (buffer+5)->ki.time = 0;
    (buffer+5)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+5)->ki.dwExtraInfo = 0;

    (buffer+6)->type = INPUT_KEYBOARD;
    (buffer+6)->ki.wVk = alt;
    (buffer+6)->ki.wScan = 0;
    (buffer+6)->ki.time = 0;
    (buffer+6)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+6)->ki.dwExtraInfo = 0;

    (buffer+7)->type = INPUT_KEYBOARD;
    (buffer+7)->ki.wVk = vk;
    (buffer+7)->ki.wScan = 0;
    (buffer+7)->ki.time = 0;
    (buffer+7)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+7)->ki.dwExtraInfo = 0;

    SendInput(8,buffer,sizeof(INPUT));
    delete(buffer);
    }

    // simple unmodified normal key event
    else
    {
    INPUT *buffer = new INPUT[2];

    buffer->type = INPUT_KEYBOARD;
    buffer->ki.wVk = vk;
    buffer->ki.wScan = 0;
    buffer->ki.time = 0;
    buffer->ki.dwFlags = 0;
    buffer->ki.dwExtraInfo =0;

    (buffer+1)->type = INPUT_KEYBOARD;
    (buffer+1)->ki.wVk = vk;
    (buffer+1)->ki.wScan = 0;
    (buffer+1)->ki.time = 0;
    (buffer+1)->ki.dwFlags = KEYEVENTF_KEYUP;
    (buffer+1)->ki.dwExtraInfo =0;

    SendInput(2,buffer,sizeof(INPUT));
    delete(buffer);
    }
    }

    Assuming I don't have typos ... Smile | :) (Big assumption) ... this fragment should hopefully illustrate the use of SendInput. And remember if you are one of our CE friends ... ignore this and stick with the Keybd_event function.






    Rich L.

    GeneralOnscreen Keyboard Pin
    amy9-Oct-00 23:48
    amy9-Oct-00 23:48 
    GeneralRe: Onscreen Keyboard Pin
    28-Mar-01 11:47
    suss28-Mar-01 11:47 
    GeneralFocus Problem Pin
    Ryan Park5-May-00 18:28
    Ryan Park5-May-00 18:28 
    GeneralNice work! Pin
    Felix23-Mar-00 8:36
    Felix23-Mar-00 8:36 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.