Faking num lock, caps lock and scroll lock leds

Introduction

Some time ago I came across a post where the author wanted to turn on and off num lock, cap lock and scroll lock led light without actually toggling their state. This sounded challenging and impossible but after some googling I found a piece of code in C for achieving exactly what I was looking for. In this post I show how it works and how to port it to C#

Toggling Keyboard Indicators from C#

The C version is available at rohitab.com As you can see from the code toggling the keyboard indicators consists of three steps:

  • Define MS-DOS device name for the target keyboard.
  • Get handle of the target keyboard.
  • Send command to the handle for changing keyboard indicators.

The first two steps are the pretty straightforward and easy to interop from C#. In order to define an MS-DOS name we need to call DefineDosDevice method pass the target keyboard path, desired MS-DOS device name and DDD_RAW_TARGET_PATH flag. The C# code looks like this:

[DllImport("kernel32.dll")]
static extern bool DefineDosDevice(uint dwFlags, string lpDeviceName, string lpTargetPath);

private const int DddRawTargetPath = 0x00000001;

We can call it like this:

DefineDosDevice(DddRawTargetPath, "keyboard", "\\Device\\KeyboardClass0");

Once we have defined Dos device name we can now use CreateFile to get handle to it. After that we use DeviceIoControl method to send IOCTL_KEYBOARD_SET_INDICATORS control code which indicates that we want to set keyboard indicator status. IOCTL_KEYBOARD_SET_INDICATORS control code is defined in Ntddkbd.h using CTL_CODE macro. In C# we can define it like this:

private const uint FileAnyAccess = 0;
private const uint MethodBuffered = 0;
private const uint FileDeviceKeyboard = 0x0000000b;

private static uint IOCTL_KEYBOARD_SET_INDICATORS =
               ControlCode(FileDeviceKeyboard, 0x0002, MethodBuffered, FileAnyAccess);

static uint ControlCode(uint deviceType, uint function, uint method, uint access)
{
    return ((deviceType) << 16) | ((access) << 14) | ((function) << 2) | (method);
}

The information about which indicators should be on and which should be off is specified by a KEYBOARD_INDICATOR_PARAMETERS structure.

The final code looks like this:

private static uint IOCTL_KEYBOARD_SET_INDICATORS = ControlCode(FileDeviceKeyboard, 0x0002, MethodBuffered, FileAnyAccess);

private const uint FileAnyAccess = 0;
private const uint MethodBuffered = 0;
private const uint FileDeviceKeyboard = 0x0000000b;
private const int DddRawTargetPath = 0x00000001;

public static void ToggleLights(Locks locks)
{
    DefineDosDevice(DddRawTargetPath, "keyboard", "\\Device\\KeyboardClass0");

    var indicators = new KeyboardIndicatorParameters();

    using (var hKeybd = CreateFile("\\\\.\\keyboard", FileAccess.Write, 0, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
    {
        indicators.UnitId = 0;
        indicators.LedFlags = locks;

        var size = Marshal.SizeOf(typeof(KeyboardIndicatorParameters));

        uint bytesReturned;
        DeviceIoControl(hKeybd, IOCTL_KEYBOARD_SET_INDICATORS, ref indicators, (uint)size,
            IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
    }
}

static uint ControlCode(uint deviceType, uint function, uint method, uint access)
{
    return ((deviceType) << 16) | ((access) << 14) | ((function) << 2) | (method);
}

struct KeyboardIndicatorParameters
{
    public ushort UnitId;
    public Locks LedFlags;
}

[Flags]
public enum Locks : ushort
{
    None = 0,
    KeyboardScrollLockOn = 1,
    KeyboardNumLockOn = 2,
    KeyboardCapsLockOn = 4
}

Conclusion

Even though toggling keyboard indicators may not be very useful porting it to C# was interesting and fun. The only real application that I was able to find is an addon for Miranda IM which uses it as a notification mechanism.

Kick It on DotNetKicks.com
Share

, ,

  • http://profiles.google.com/thomas.levesque Thomas Levesque

    Nice! I remember doing the same thing in Pascal 15 years ago, using blocks of assembly code… it was more obscure, but also much shorter ;)

  • Joshua DeLong

    It looks like your code is missing some stuff compared to the basic C version. You have a call to 
    CreateFile  that is missing a P/Invoke declaration unless your really going to use FileStream. You also don’t have a P/Invoke declaration for 
    DeviceIoControl .

    • http://www.aboutmycode.com/ Giorgi Dalakishvili

      Joshua,

      You are correct that the code is missing P/Invoke declaration for those methods but it should be pretty straightforward to declare them.

      • Eduardo

        Can you please share your code for declaring these 2 P/Invokes? Would definetelly make your code snippet much quicker to get working…

More in c#, interop
Building Expression Evaluator with Expression Trees in C# – Improving the Api

In previous part we added support for variables but it has a big disadvantage: values of the variables are bound by position and not by name. This means that you should pass values for the variables in the same order as they appear in the expression. On the other hand binding by name has following advantages: If you change the expression you do not have to worry about keeping order of the variables you pass in sync. So in this post we are going to change expression evaluator to bind parameters by name. We will also add a new overload for better performance when we need to evaluate same expression with different parameter values.

Using Reactive Extensions for Streaming Data from Database

You have probably heard about Reactive Extensions, a library from Microsoft that greatly simplifies working with asynchronous data streams and...