Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Virtual On-Screen Keyboard Example

0.00/5 (No votes)
15 Jan 2009 1  
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 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