Dynamic Hotkey Support

Thursday, August 18 2005 @ 04:33 PM CEST

Contributed by: guyonasm

Level : beginner

OS : windows
Language : C

Written by: Daniel S. Millington (guyonasm@hotmail.com)

Introduction

This article will introduce the concept of dynamic hotkeys within a program.
A Hotkey is a combination of one or more keys simultaneously pressed in which
then causes an action to occur. For example, pressing alt+f4 terminates an
application.

Where dynamic comes into play is how the key combinations are
"figured out", so to speak. The key combinations are stored within an INI file
and from there read into the program. The advantages to this and the method
that will soon be introduced are:


The Concept

Now obviously, we will need an expandable data structure to store information
that we need. More specifically the combination of keys that make up our
hotkeys. It must be dynamic, meaning we can alter its size and state at will.
To cover this we will use a linked-list data structure as so:
struct Key
{
	int vKey;
	struct Key *nKey;
};
vKey stores the virtual keycode of the key, and nKey links us to the next key
(if there is one). We fill this list by parsing the string representation of the
hotkey stored within the INI file. Here is a simple function that parses the
string and creates the list that will makeup our hotkey combination list.
void parseHotkey (char *s, struct Key *k)
{
	struct Key *front;
	
	k->vKey = 0;
	k->nKey = 0;
	
	front = k;
	
	if (strtok (s, "+") == 0)
	{
		k->vKey = getKeyCode (s);
		return;
	}
		k->vKey = getKeyCode (s);
	
	while (s = strtok (0, "+"))
	{
		k->nKey = (struct Key *)malloc (sizeof (struct Key));
		k = k->nKey;
		k->vKey = getKeyCode (s);
		k->nKey = 0;
	}
		k = front;
}
The first parameter of the function takes the string representation of our
hotkey, and the second is a pointer to our linked-list data structure. All should
be self explanatory. It splits the string at "+", therefore there should be no
spaces in the string. Something not explained is of course, getKeyCode. This
function takes the string representation of our key, and returns the virtual
keycode of it. A standard keyboard has about 101 keys, and others have more.
It would be pointless to code in all of the virtual keys, so for this example
we will only use 3 different keys, if you want more you can look them up.
int getKeyCode (char *s)
{
	if (s == 0)
		return -1;
		
	if (!strcmp (s, "alt") || !strcmp (s, "ALT"))
		return VK_MENU;

	else if (!strcmp (s, "1"))
		return 0x31;
		
	else if (!strcmp (s, "2"))
		return 0x32;
	else
		return -1;
}
Okay, that is pretty straight forward. Now although most current systems
will do this for you, it is good to clean up after yourselves. So here is a function
to free the memory allocated for each list:
void cleanKey (struct Key *k)
{
	struct Key *temp;
	while (k != 0)
	{
		temp = k;
		k = k->nKey;
		free (temp);
	}
}
Now, to walk through and see if a key combination is pressed, we simply check
each link in the list, and if it is true (meaning the key is pressed), then we
move onto the next key in the combination. If all the keys are pressed then
the hotkey has been triggered, and we can execute whatever action was
assigned to it. Here is an example. There are many ways to go about this:

int checkKeys (struct Key *k)
{
	struct Key *temp;
	
	temp = k;
	while (k)
	{
		if (GetAsyncKeyState (k->vKey) < 0)
                {
                        if (k->nKey == 0)
			{
				// we made it here, hotkey triggered
				k = temp;
				return 1;
			}
		}
		else
			break;
		
		k = k->nKey;
	}
	k = temp;
	return 0;
}
If the hotkey is triggered 1 is returned, otherwise its 0.

An Implementation

So, now that we've covered all of the important things, and pretty much the
goal of the article. An example of using this, although rather useless would be
to create a program with 2 hotkeys. It sits in the background and waits for
either of them to be pressed. The first creates a MessageBox with a message.
The other exits the program, and pops up a MessageBox stating so. Here is
the code for this simple implementation:

// We are assuming everything else needed has been defined
// you, just can't see it. This program will not compile as is
// you are missing the necessary declarations of all of the functions
// Listed above.

// Also the hotkeys are hardcoded. We do not read in from any
// External Source. This was just to make the code shorter.
// You read in the string from an external source, and then pass
// it as the first parameter to parseHotkey.

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

struct Key *mkey=0, *exitkey=0;

int working = 1;

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)
{				mkey = (struct Key *)malloc (sizeof (struct Key));
	exitkey = (struct Key *)malloc (sizeof (struct Key));
			
	parseHotkey ("alt+1", mkey);
	parseHotkey ("alt+2", exitkey);
			
	while (working)
	{
		if (checkKeys (mkey))
			MessageBox (0, "Hotkey #1 triggered!", "Notice.", 0);
		else if (checkKeys (exitkey))
		{
			MessageBox (0, "Hotkey #2 triggered! Exiting Program.", "Notice.", 0);
			working = 0;
		}
		Sleep (10);
	}
				cleanKey (mkey);
	cleanKey (exitkey);
	
	return 0;
}
And that is it. It is hoped that at least one person found this useful. If not, it
was still rather enjoyable writing it.

6 comments



http://www.reversing.be/article.php?story=20050818163329113