Lack of Information – Programmatically Toggling the LOCK keys from VB.NET

 

As usual my blog entries arise from questions I’ve looked into for people. Today someone asked me how to toggle the NUMLOCK key from VB.NET. I thought to myself that surely there must be a sample somewhere?

There was none…(at least nothing I could find within 5 minutes searching both our knowledgebase and googling for it.). Astonishing isn’t it!

So, below is a sample that shows you how to toggle the NUMLOCK and CAPSLOCK keys. What I did to get this was I took Q177674 HOWTO: Toggle the NUM LOCK, CAPS LOCK, and SCROLL LOCK Keys, created the VB6 project. I then used the VS.NET 2003 upgrade wizard to convert this project to VB.NET. The KB article only has code to turn on the LOCK keys if they are off so I modified the code to actually toggle the keys. All you have to do is create a new winforms app, add a button to the form and paste the code below into the form’s class.

Of course with the advent of Visual Studio .NET 2005 you can simply use the My classes to access a managed way to do this…it’s much, much simpler. J

   ' Declare Type for API call:

    Private Structure OSVERSIONINFO

        Dim dwOSVersionInfoSize As Integer

        Dim dwMajorVersion As Integer

        Dim dwMinorVersion As Integer

        Dim dwBuildNumber As Integer

        Dim dwPlatformId As Integer

        <VBFixedString(128), System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=128)> Public szCSDVersion As String ' Maintenance string for PSS usage

    End Structure

    ' API declarations:

    'UPGRADE_WARNING: Structure OSVERSIONINFO may require marshalling attributes to be passed as an argument in this Declare statement. Click for more: 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="vbup1050"'

    Private Declare Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (ByRef lpVersionInformation As OSVERSIONINFO) As Integer

    Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)

    Private Declare Function GetKeyboardState Lib "user32" (ByRef pbKeyState As Byte) As Integer

    Private Declare Function SetKeyboardState Lib "user32" (ByRef lppbKeyState As Byte) As Integer

    ' Constant declarations:

    Const VK_NUMLOCK As Short = &H90S

    Const VK_SCROLL As Short = &H91S

    Const VK_CAPITAL As Short = &H14S

    Const KEYEVENTF_EXTENDEDKEY As Short = &H1S

    Const KEYEVENTF_KEYUP As Short = &H2S

    Const VER_PLATFORM_WIN32_NT As Short = 2

    Const VER_PLATFORM_WIN32_WINDOWS As Short = 1

    Private Sub Button1_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Button1.Click

        Dim o As OSVERSIONINFO

        Dim NumLockState As Boolean

        Dim ScrollLockState As Boolean

        Dim CapsLockState As Boolean

        o.dwOSVersionInfoSize = Len(o)

        GetVersionEx(o)

        Dim keys(255) As Byte

        GetKeyboardState(keys(0))

        ' NumLock handling:

        NumLockState = keys(VK_NUMLOCK)

        If NumLockState <> True Then 'Turn numlock on

            If o.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then '=== Win95/98

                keys(VK_NUMLOCK) = 1

                SetKeyboardState(keys(0))

            ElseIf o.dwPlatformId = VER_PLATFORM_WIN32_NT Then '=== WinNT

                'Simulate Key Press

                keybd_event(VK_NUMLOCK, &H45S, KEYEVENTF_EXTENDEDKEY Or 0, 0)

                'Simulate Key Release

                keybd_event(VK_NUMLOCK, &H45S, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)

            End If

        Else

            If o.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then '=== Win95/98

                keys(VK_NUMLOCK) = 0

                SetKeyboardState(keys(0))

            ElseIf o.dwPlatformId = VER_PLATFORM_WIN32_NT Then '=== WinNT

                'Simulate Key Press

                keybd_event(VK_NUMLOCK, &H45S, KEYEVENTF_EXTENDEDKEY Or 0, 0)

                'Simulate Key Release

                keybd_event(VK_NUMLOCK, &H45S, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)

            End If

        End If

        ' CapsLock handling:

        CapsLockState = keys(VK_CAPITAL)

        If CapsLockState <> True Then 'Turn capslock on

            If o.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then '=== Win95/98

                keys(VK_CAPITAL) = 1

                SetKeyboardState(keys(0))

            ElseIf o.dwPlatformId = VER_PLATFORM_WIN32_NT Then '=== WinNT

                'Simulate Key Press

                keybd_event(VK_CAPITAL, &H45S, KEYEVENTF_EXTENDEDKEY Or 0, 0)

                'Simulate Key Release

                keybd_event(VK_CAPITAL, &H45S, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)

            End If

        Else

            If o.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then '=== Win95/98

                keys(VK_CAPITAL) = 0

                SetKeyboardState(keys(0))

            ElseIf o.dwPlatformId = VER_PLATFORM_WIN32_NT Then '=== WinNT

                'Simulate Key Press

                keybd_event(VK_CAPITAL, &H45S, KEYEVENTF_EXTENDEDKEY Or 0, 0)

                'Simulate Key Release

                keybd_event(VK_CAPITAL, &H45S, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)

            End If

        End If

        ' ScrollLock handling:

        ScrollLockState = keys(VK_SCROLL)

        If ScrollLockState <> True Then 'Turn Scroll lock on

            If o.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS Then '=== Win95/98

                keys(VK_SCROLL) = 1

                SetKeyboardState(keys(0))

            ElseIf o.dwPlatformId = VER_PLATFORM_WIN32_NT Then '=== WinNT

                'Simulate Key Press

                keybd_event(VK_SCROLL, &H45S, KEYEVENTF_EXTENDEDKEY Or 0, 0)

                'Simulate Key Release

                keybd_event(VK_SCROLL, &H45S, KEYEVENTF_EXTENDEDKEY Or KEYEVENTF_KEYUP, 0)

            End If

        End If

    End Sub