Toggling the Num Lock, Caps Lock, and Scroll Lock keys






4.84/5 (23 votes)
How to toggle the Num Lock, Caps Lock, and Scroll Lock keys programmatically
Introduction
I have a status bar that toggles the Num Lock, Caps Lock and Scroll Lock keys in one application, but some time ago, I discovered that the API function SendInput
I used for it requires Windows 98 or later and Windows NT 4.0 with Service Pack 3.0 or later. I have browsed MSDN and found that there are two more functions that can toggle keyboard state but each of them has some specific limitations like SendInput
does. To make it easier for others, I have posted all possible variants with their descriptions and limitations and a simple solution for toggling these keys avoiding compatibility problems.
Variant A - using keybd_event
Description
The keybd_event
function synthesizes a keystroke. The system can use such a synthesized keystroke to generate a WM_KEYUP
or WM_KEYDOWN
message. The keyboard driver's interrupt handler calls the keybd_event
function.
Version Computability
- Windows NT/2000/XP: Requires Windows NT 3.1 or later
- Windows 95/98/ME: Requires Windows 95 or later
- Windows CE: Requires version 1.0 or later
Important Notes
- An application can simulate a press of the PRINTSCRN key in order to obtain a screen snapshot and save it to the clipboard. To do this, call
keybd_event
with the first parameter set toVK_SNAPSHOT
. - Windows 95/98/Me: The
keybd_event
function can toggle only the CAPS LOCK and SCROLL LOCK keys. It cannot toggle the NUM LOCK key. We can do this withSendInput
but it requires Windows NT 4.0 SP3 and later or Windows 98 and later. - Windows NT/2000/XP: The
keybd_event
function can toggle the NUM LOCK, CAPS LOCK, and SCROLL LOCK keys.
Sample Usage
When setting key state, be sure to generate both key press and key release (see below). Notes: Windows NT/2000: This function has been superseded. Use SendInput
instead.
//
// Toggle Caps Lock key:
::keybd_event( VK_CAPITAL, 0x45, KEYEVENTF_EXTENDEDKEY, 0 );
::keybd_event( VK_CAPITAL, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 );
//
Variant B - using SendInput
Description
The SendInput
function synthesizes keystrokes, mouse motions, and button clicks.
Version Compatibility
- Windows NT/2000/XP: Requires Windows NT 4.0 SP3 or later
- Windows 95/98/Me: Requires Windows 98
- Windows CE: Requires version 2.0 or later
Sample Usage
When setting key state, be sure to generate both key press and key release (see below). And do not forget to include WinAble.h, not WinUser.h as MSDN says.
//
#include <WinAble.h> // Required for the ::SendInput function
//...
// Toggle Caps Lock key:
INPUT input[2];
::ZeroMemory(input, sizeof(input));
input[0].type = input[1].type = INPUT_KEYBOARD;
input[0].ki.wVk = input[1].ki.wVk = VK_CAPITAL;
input[1].ki.dwFlags = KEYEVENTF_KEYUP; // THIS IS IMPORTANT
::SendInput(2, input, sizeof(INPUT));
//
Variant C - using SetKeyboardState
Description
The SetKeyboardState
function copies a 256-byte array of keyboard key states into the calling thread's keyboard-input state table.
Version Compatibility
- Windows NT/2000/XP: Requires Windows NT 3.1 or later
- Windows 95/98/Me: Requires Windows 95 or later
- Windows CE: Unsupported
Important Notes
- Because the
SetKeyboardState
function alters the input state of the calling thread and not the global input state of the system, an application cannot useSetKeyboardState
to set the NUM LOCK, CAPS LOCK, or SCROLL LOCK indicator lights on the keyboard. SetKeyboardState
function sets keyboard state for calling thread only, not the global input state of the system.
Sample Usage
//
// Toggle Caps Lock key:
BYTE byKeybState[256];
::GetKeyboardState(byKeybState);
byKeybState[nVirtKey] = !(BOOL)::GetKeyState(VK_CAPITAL);
::SetKeyboardState(byKeybState);
//
Support for Setting Num Lock, Caps Lock and Scroll Lock Keys State
Function\OS
| Win CE 1.0
| Win CE 2.0
| Win 95
| Win 98/Me
| Win NT
| Win 2000/XP
|
keybd_event | Yes
| Yes
| All but Num Lock
| All but Num Lock
| Yes
| Yes
|
SendInput | | Yes
| | Yes
| SP3*
| Yes
|
SetKeyboardState | | | Yes**
| Yes**
| Yes**
| Yes**
|
* - Requires Service Pack 3 or later.
** - Does not set indicator lights on the keyboard and toggles input state of the calling thread only.
Simple Solution
I have provided a simple StatusBar
class that toggles the keys when the appropriate pane is double-clicked. See below:
//
#include <WinAble.h> // Required for the ::SendInput function
//...
void CStatusBarEx::OnNMDblclk(NMHDR* pNMHDR, LRESULT *pResult)
{
// Get the double-clicked pane index:
NMMOUSE* pNMMOUSE = (NMMOUSE*)pNMHDR;
INT nInd = GetItemID((int)pNMMOUSE->dwItemSpec);
if((nInd >= ID_INDICATOR_CAPS) &&
(nInd <= ID_INDICATOR_OVR))
{
UINT nVirtKey = 0;
switch(nInd)
{
case ID_INDICATOR_CAPS: nVirtKey = VK_CAPITAL; break;
case ID_INDICATOR_NUM: nVirtKey = VK_NUMLOCK; break;
case ID_INDICATOR_SCRL: nVirtKey = VK_SCROLL; break;
case ID_INDICATOR_OVR: nVirtKey = VK_INSERT; break;
}
ASSERT(nVirtKey >= 1 && nVirtKey<= 254);
DWORD dwVersion = ::GetVersion();
// Windows NT/2000/XP: The keybd_event function can toggle the
// NUM LOCK, CAPS LOCK, and SCROLL LOCK keys although
// this function has been superseded by ::SendInput.
if( dwVersion < 0x80000000) // Win NT
{
::keybd_event( nVirtKey, 0x45, KEYEVENTF_EXTENDEDKEY, 0 );
::keybd_event( nVirtKey, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0 );
}
else
{
// Windows 95/98/Me: The keybd_event function can toggle only the
// CAPS LOCK and SCROLL LOCK keys. It cannot toggle the NUM LOCK key.
// We can do this with SendInput but it requires
// Windows NT 4.0 SP3 and later or Windows 98 and later.
DWORD dwMin = (DWORD)(HIBYTE(LOWORD(dwVersion)));
if(dwMin >= 10) // Windows 98 and later
{
INPUT input[2];
::ZeroMemory(input, sizeof(input));
input[0].type = input[1].type = INPUT_KEYBOARD;
input[0].ki.wVk = input[1].ki.wVk = nVirtKey;
input[1].ki.dwFlags = KEYEVENTF_KEYUP; // THIS IS IMPORTANT
::SendInput(2, input, sizeof(INPUT));
}
else // Windows 95
{
// Because the SetKeyboardState function alters the input state
// of the calling thread and not the global input state of the system,
// an application cannot use SetKeyboardState to set the
// NUM LOCK, CAPS LOCK, or SCROLL LOCK (or the Japanese KANA) indicator
// lights on the keyboard.
BYTE byKeybState[256];
::GetKeyboardState(byKeybState);
byKeybState[nVirtKey] = !(BOOL)::GetKeyState(nVirtKey);
::SetKeyboardState(byKeybState);
}
}
::Beep(500, 100);
}
else
{
CWnd* pWnd = GetParent();
if(pWnd != NULL)
{
//TODO: SendNotifyMessage;
}
}
*pResult = 0;
}
//
Please send me all bugs, fixes or better solutions.
History
- 25th May, 2002: Initial version