Introduction
A few months ago, I was developing a desktop application for a client. After completing the requirements, I was enhancing the UI specially the main form. In the previous versions of Microsoft Word (before version 2007), there are some labels which are clickable and reflect the changes to the keyboard (details below) and I wanted to add these features to my applications.
HTML documentation of the code has also been included along the source in the zip file. Select the index.html in the HTML folder to view it.
Toggle Keys
There are three LEDs on almost every keyboard, i.e. NUM lock, CAPS lock and SCROLL lock. These LEDS shows the status of the respective keys. As these keys are either in ON state or OFF state, their value is toggled between 1 and 0, so these are called Toggle Keys. The INSERT key is also included in toggle keys, although there is no LED for it but its value is either ON (insert mode) or OFF (overwrite mode), so it is also included in this category.
In my application, I wanted to add the status of NUM lock and CAPS lock. I Googled it and got a solution using Microsoft.VisualBasic.Devices
. It was a pretty simple solution but with some limitation. You can only read the status of the keys, no method to set the status of the keys. (I am not going to discuss this here, I might write a separate post for it). The application deadline was very close and I was not able to implement this extra feature as I had planned. Since this feature was not requested by the client, it was delivered with read only options.
Objective
The objective of the post is to get and set the CAPS lock and NUM lock, etc. from the application.
Background
WIN32 API provides a lot of low level functions to access the system hardware. Due to high level of security, these features are not directly available in .NET Framework. To perform low level interaction with hardware, we have to call the WIN32 API methods in .NET using some special syntax.
For this purpose, System.Runtime.InteropServices
namespace must be included.
Following the C language style, we have to declare the function so that we could use the method in the code.
Declaration
[DllImport("APIname.dll")]
internal static extern returnType
MethodName (argument(s));
Usage
You can use this method as any other local method:
int nvar = Win32APIMethodName();
WIN32 API Methods Used
Two methods of WIN32 API have been used to achieve the desired results.
[DllImport("user32.dll")]
internal static extern short GetKeyState(int keyCode);
The GetKeyState
method returns the status of the key specified through the key code argument. Return value will be 0 if off and 1 if on.
Parameter
keyCode
: Specifies a virtual-key code for the key to be checked. The code must be a value in the range 1 to 254. For a complete list, see Virtual-Key Codes.
Please check MSDN for a complete description.
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
This function is useful to simulate Key presses to the window with focus.
Parameters
bVk
: Specifies a virtual-key code. The code must be a value in the range 1 to 254. For a complete list, see Virtual-Key Codes.
bScan
: Specifies a hardware scan code for the key.
dwFlags:
Specifies various aspects of function operation. Normally KEYEVENTF_EXTENDEDKEY
or KEYEVENTF_KEYUP
are used. If specified, the key is being released. If not specified, the key is being depressed.
dwExtraInfo
: Specifies an additional value associated with the key stroke.
Please check MSDN for complete description.
Note: In the test application, instead of the Virtual key Codes, we will be using System.Keys
enumeration where required.
Creating a Test Application
Create a new Windows Application Project in C#. From Menus & Toolbar section of the control box, add a Status Strip on your form. Add three labels to the status strip. Name them as lblINS, lblNUM and lblCAPS respectively. It is better to set their width to 40.
Set the DoubleClickEnabled
property of these labels to true
.
Set the AutoSize
property of these labels to false
.
Generate the DoubleClick
event for these labels to handle the double click action, e.g.
private void lblNUM_DoubleClick(object sender, EventArgs e)
{
PressKeyboardButton(Keys.NumLock);
UpdateNUMLock();
}
Form Events
Set the KeyPreview
property of the form to true
. This will help to pass the keys pressed on the child controls to the parent control (form) (for better understanding of the property, build the attached test application with this property set to false
).
In the design view, double click the form to generate its Form_Load
event and call the method UpdateKeys
. It will read the current status of the keys and update the form accordingly.
private void Form1_Load(object sender, EventArgs e)
{
UpdateKeys();
}
Generate the Form1_KeyUp
event of the form to handle the key press event (this event is raised when a key is pressed and then released).
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Insert)
{
UpdateInsert();
}
else if (e.KeyData == Keys.NumLock)
{
UpdateNUMLock();
}
else if (e.KeyData == Keys.CapsLock)
{
UpdateCAPSLock();
}
}
Utility Methods
PressKeyboardButton
This method takes the key code as parameter and simulates a key press event by sending a Key-Down message to the operating system followed by a Key-Up message.
private void PressKeyboardButton(Keys keyCode)
{
const int KEYEVENTF_EXTENDEDKEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;
keybd_event((byte)keyCode, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event((byte)keyCode, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
UpdateNUMLock
It reads the status of the NUM lock using GetKeyState
and updates the form accordingly.
this.Refresh()
has been called at the end to ensure the form update by sending a Redraw request.
private void UpdateNUMLock()
{
bool NumLock = (GetKeyState((int)Keys.NumLock)) != 0;
if (NumLock)
{
lblNUM.Text = "NUM";
}
else
{
lblNUM.Text = String.Empty;
}
this.Refresh();
}
Similarly, the other methods for CAPS lock and INSERT can also be implemented.
Conclusion
Your application will be able to reflect the status of the toggle keys. Also you can update the status of these keys from your application by double clicking the labels in the status strip.
Although I have been reading the articles and blogs for a long time, now I decided to make my contribution by sharing my knowledge and experience. I would love to get your feedback on this and do not forget to rate the post if you like it.
History
- 2008/05/24 1.0.0.0 First release