Click here to Skip to main content
Licence CPOL
First Posted 15 Jan 2009
Views 26,409
Downloads 1,355
Bookmarked 22 times

Virtual On-Screen Keyboard Example

By | 15 Jan 2009 | Article
A simple MFC dialog-based framework that mimics the behavior of the MS On-Screen Keyboard.

Introduction

A dialog can send key input to any foreground window without itself being activated to function as an on-screen keyboard. Regular windows get activated and focused when they are clicked or something. To avoid this, a window needs to be a non-activating window. You can do this by creating a window with the "WS_EX_NOACTIVATE" extended style, or by modifying its style using "ModifyStyleEx". But, with this style, a window behaves somewhat differently than expected when you move the window. To solve this, you need to provide your own implementations for the "WM_NCLBUTTONDOWN" and "WM_MOUSEMOVE" messages to behave the same way as the system-provided On-Screen Keyboard does. This code shows how to do this and send your own keyboard inputs to any foreground window using the newly-introduced "SendInput" system function.

Background

One day, I needed to implement a virtual On-Screen Keyboard that received signals - through a COM (serial) port - from a custom input device and then sent keyboard inputs to the system according to the signals. While doing this, I came to know about the On-Screen Keyboard accessory application provided by Windows, and wanted my application to behave similar to that. But, it was not as trivial a task as I first expected, because of the "focus" and "activation" problems. In this example, you will find that avoiding those problems could be done in a simple way.

Using the code

This is a VC++ 9.0 project.

Firstly, you need to create an MFC dialog-based application. And then, to make the dialog a non-activating topmost window, you need to change its "No Activate" and "Topmost" resource properties to "true".

Then, handle "WM_NCLBUTTONDOWN" message. This is for making the dialog temporarily behave as a regular window without the "WS_EX_NOACTIVATE" style so that it can move smoothly.

void COnScreenKeyboardDlg::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
 if (!m_hForegroundWnd)
 {
  // store current foreground window
  m_hForegroundWnd = ::GetForegroundWindow();
  // temporarily make this dialog an activatable window
  ModifyStyleEx(WS_EX_NOACTIVATE,0);
  // make this dialog foreground
  SetForegroundWindow();
 }
 CDialog::OnNcLButtonDown(nHitTest, point);
}

Now, handle the "WM_MOVE" message. This is for making the dialog behave again as a non-activating window when the mouse pointer moves around in the client area, and for making any previous foreground window active. This is the exact behavior the system-provided On-Screen Keyboard shows.

void COnScreenKeyboardDlg::OnMouseMove(UINT nFlags, CPoint point)
{
 if (m_hForegroundWnd)
 {
  // make the previous foreground window active
  ::SetForegroundWindow(m_hForegroundWnd);
  // make this dialog non-activating
  ModifyStyleEx(0,WS_EX_NOACTIVATE);
  // set it to NULL to mark that we do not need to do this again
  m_hForegroundWnd = NULL;
 }
 CDialog::OnMouseMove(nFlags, point);
}

Now, to send an arbitrary key input to the system, you can use the "SendInput" function. Here, I send the "x" (virtual code 88) key input as an example when the "Send X" button in the dialog is clicked.

void COnScreenKeyboardDlg::OnBnClickedSendX()
{
 INPUT keyInput;
 keyInput.type = INPUT_KEYBOARD;
 KEYBDINPUT key;
 key.wVk = 88;
 key.wScan = ::VkKeyScan(88);
 key.dwFlags = 0;
 keyInput.ki = key;
 ::SendInput(1,&keyInput,sizeof(INPUT));
 key.dwFlags = KEYEVENTF_KEYUP;
 keyInput.ki = key;
 ::SendInput(1,&keyInput,sizeof(INPUT));
}

Points of interest

Code samples I have found on the Internet do this in an overly complicated manner using the "AttachThreadInput" function. As you can see, making a window behave the same way as the Windows On-Screen Keyboard can be done in a simple way using the "WS_EX_NOACTIVATE" style and some other small tricks.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

visubong



Korea (Republic Of) Korea (Republic Of)

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Generalvirtual on screen keyboard Pinmembershriisha2:44 20 Jun '09  
QuestionCan key logger read your keys when you press button down? PinmemberMember 35297778:35 19 Jun '09  
GeneralIt was somewhat buggy. Here goes the correction. Pinmembervisubong3:50 16 Jan '09  
GeneralRe: It was somewhat buggy. Here goes the correction. Pinmemberbnnkyw16:50 17 Apr '11  
GeneralVirtual On-Screen Keyboard Example Pinmembersnprani20:02 15 Jan '09  

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

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 15 Jan 2009
Article Copyright 2009 by visubong
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid