PDA

View Full Version : Dynamic Key Handler


freezzo
10-29-2007, 01:50 PM
I want to write a very robust and dynamic key handler that I could use in a game and I was hoping for some ideas about how to go about it.

I could like to make it flexible enough so that I can do something such as:

keyHandler->Bind(KEYTOBIND, functionToRun);


Then in my while loop:

while(!done)
{
keyHandler->poll();
}


The biggest thing this would need to do, is be able to add multiple functions to one key so that depending on the state of an object(IE mouse being over an object for picking or over an inventory bag) it would execute the proper function.

I'm not even sure if this makes sense to do this way or not, so any ideas would be helpful.

freezzo
10-29-2007, 01:53 PM
The other possibility I was thinking is having every function that does some action based on input to be attached to an event, so that when the event is activated based on that functions criteria, it would execute it. If this is more applicable, what would be some ideas to go about that?

SamuraiCrow
10-29-2007, 03:44 PM
Are you trying to make a graphical adventure game like the old LucasArts SCUMM engines (Monkey Island series, Maniac Mansion, etc.)?

If so, the source code to the ScummVM engine is found at this SourceForge project page (http://sourceforge.net/projects/scummvm/). It's probably not the most readable but it is one place to look.

Jare
10-29-2007, 11:07 PM
You may want a level of indirection:

1 - keys generate events

2 - functionality is bound to events.

For example, a single key can generate 4 types of events: when pushed, when released, when it is down, and when it is up.

What you describe about mouse over UI objects is somewhat separate, in that the mouse can select the target of those events, i.e. the 2nd list.

It can get quite complex, so start simple and improve / refactor as you go.

monjardin
10-30-2007, 06:25 PM
class KeyHandler {
public:
virtual ~KeyHandler() {}
virtual void keyPressEvent(int key) = 0;
};

class SomeKeyHandler : public KeyHandler {
public:
void keyPressEvent(int key) {
// do something with context data according to the key pressed
}

private:
// context data goes here
};

// class SomeOtherKeyHandler ...

// now use polymorphism
SomeKeyHandler kh1;
SomeOtherKeyHandler kh2;
KeyHandler *p = &kh1;
p->keyPressEvent('1');
p = &kh2;
p->keyPressEvent('2');

// now bind them to keys
KeyHandler *array[MAX_UCHAR];
memset(array, 0, sizeof (array));
array['1'] = &kh1;
array['2'] = &kh2;
char key = '1';
if (array[key])
array[key]->keyPressEvent(key);

// or like this
std::map<char, KeyHandler*> keyMap;
keyMap.insert(make_pair('1', &kh1));
keyMap.insert(make_pair('2', &kh2));
key = '2';
std::map<char, KeyHandler*>::iterator it = keyMap.find(key);
if (keyMap.end() != it)
it->second->keyPressEvent(key);


I've found the state pattern (http://en.wikipedia.org/wiki/State_pattern) very useful when dealing with input of this nature.

GUI toolkits typically track keyboard focus (or use mouse over in your example) to determine the target these events. Often a widget can eat the event or pass it on to its parent (i.e. the chain-of-responsibility pattern (http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern)).

You may want to build a data structure where multiple layers of key handlers can use a key if they are bound to it, or pass it along to super states otherwise.

The action mapping of Direct Input (http://msdn2.microsoft.com/en-us/library/bb206287.aspx) is another approach.