Link to home
Start Free TrialLog in
Avatar of Rapido
Rapido

asked on

SetKeyboardState not working (InterOp, user32.dll)

My employer has a problem with the numlock status randomly changing during data entry. I need to write a background app that polls the numlock state regularly, and re-activates it if it is randomly deactivated. I've got the polling part working perfectly, but when setting the state (SetKeyboardState returns true) the lights don't go on / off, and the effect doesn't trigger either. Here's the code I used:

First I import the functions I need from user32.dll:

[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true, CallingConvention=CallingConvention.Winapi)]
public static extern bool SetKeyboardState( byte[] keys );
            
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true, CallingConvention=CallingConvention.Winapi)]
public static extern bool GetKeyboardState( byte[] keys );

Then I read the current state into a byte array:

Byte[] myBytes = new Byte[256];
GetKeyboardState(myBytes);

Set the relevant virtual keys to 'true':

myBytes[144] = 0; // NumLock
myBytes[145] = 0; // ScrollLock (just for testing)
myBytes[20] = 0; // CapsLock (just for testing)

And reload the changed byte array into the keyboard state:

SetKeyboardState(myBytes);

There aren't too many examples on the web, so I'm hoping someone's done this successfully before.
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Rapido
Rapido

ASKER

Yeah, that's the function I ended up using. Suppose I asked the question a bit too soon. Works perfectly now. I'll post the code here tomorrow and then I'll give you the points, so we can wrap this up.
Avatar of Rapido

ASKER

To import the function:

[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true, CallingConvention=CallingConvention.Winapi)]
public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int extraInfo);

To depress, press, and depress the numlock key:

keybd_event(144, 0, 2, 0);
keybd_event(144, 0, 0, 0);
keybd_event(144, 0, 2, 0);

Turned out you need to depress it first, in case it's still being pressed during the time you want it to reactivate. Strange how MS throws about all kinds of constants, but that there pretty impossible to look up in vs.net. Oh well, problem solved in any case.