Click here to Skip to main content
15,860,972 members
Articles / Desktop Programming / MFC

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

Rate me:
Please Sign up or sign in to vote.
4.84/5 (23 votes)
24 May 2002CPOL3 min read 251.6K   7K   65   41
How to toggle the Num Lock, Caps Lock, and Scroll Lock keys programmatically
There are two more functions that can toggle keyboard state but each of them has some specific limitations like SendInput does. In this article, you will find all possible variants with their descriptions and limitations and a simple solution for toggling these keys avoiding compatibility problems.

Image 1

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

  1. 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 to VK_SNAPSHOT.
  2. 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.
  3. 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.

C++
//
    // 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.

C++
//
    #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

  1. 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 indicator lights on the keyboard.
  2. SetKeyboardState function sets keyboard state for calling thread only, not the global input state of the system.

Sample Usage

C++
//
    // 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

Sample Image

I have provided a simple StatusBar class that toggles the keys when the appropriate pane is double-clicked. See below:

C++
//
#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

License

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


Written By
Software Developer (Senior) SafeNet Inc
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

 
QuestionDoes it work in Vista and newer and could it be used for Fn/windows keys? Pin
TeknoRapture26-Feb-15 19:28
TeknoRapture26-Feb-15 19:28 
QuestionSendInput not displaying in Win98 Dos Box Pin
SirGuyon2-Dec-08 22:20
SirGuyon2-Dec-08 22:20 
AnswerRe: SendInput not displaying in Win98 Dos Box Pin
Armen Hakobyan4-Dec-08 6:03
professionalArmen Hakobyan4-Dec-08 6:03 
GeneralRe: SendInput not displaying in Win98 Dos Box Pin
SirGuyon4-Dec-08 12:24
SirGuyon4-Dec-08 12:24 
AnswerRe: SendInput not displaying in Win98 Dos Box Pin
SirGuyon4-Dec-08 19:09
SirGuyon4-Dec-08 19:09 
Generalgenerate all charecters of a charecter set Pin
17-Aug-04 10:07
suss17-Aug-04 10:07 
GeneralRe: &amp;#52852;&amp;#46300;&amp;#49324; &amp;#51204;&amp;#54868; &amp;#48155;&amp;#44592;/&amp;#48730; &amp;#50504;&amp;#44058;&amp;#44256; &amp;#50724;&amp;#47000; &amp;#48260;&amp;#54000;&amp;#44592; &amp;#50836;&amp;#47161; Pin
Armen Hakobyan18-Apr-04 8:57
professionalArmen Hakobyan18-Apr-04 8:57 
GeneralDid not work 'Num Lock' in Win98. Pin
Behzad Ebrahimi9-Dec-03 1:18
Behzad Ebrahimi9-Dec-03 1:18 
GeneralGenerate a ALT 0128 combinations Pin
percyvimal28-Nov-03 18:42
percyvimal28-Nov-03 18:42 
GeneralRe: Generate a ALT 0128 combinations Pin
Anonymous29-Nov-03 17:53
Anonymous29-Nov-03 17:53 
GeneralSendInput to IE from Band Object Pin
Rod_Stein26-Oct-03 16:27
Rod_Stein26-Oct-03 16:27 
GeneralUsing SendInput Pin
phlipping25-Jul-03 21:51
phlipping25-Jul-03 21:51 
GeneralDoesn't work with Microsoft keyboards... : ( Pin
Snyp18-Jun-03 16:09
Snyp18-Jun-03 16:09 
GeneralRe: Doesn't work with Microsoft keyboards... : ( Pin
Snyp18-Jun-03 16:14
Snyp18-Jun-03 16:14 
General<WinAble> NOT WinUser Pin
derchris10-May-03 15:50
derchris10-May-03 15:50 
GeneralRe: &lt;WinAble&gt; NOT WinUser Pin
llllskywalker20-Oct-03 8:07
llllskywalker20-Oct-03 8:07 
GeneralSENDINPUT Pin
Anonymous27-Sep-02 8:25
Anonymous27-Sep-02 8:25 
GeneralRe: SENDINPUT Pin
MaxiGroovy16-Jan-03 3:01
MaxiGroovy16-Jan-03 3:01 
Generalthanks Pin
4-Jun-02 3:07
suss4-Jun-02 3:07 

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.