Handling keyboard/mouse input

Started by
27 comments, last by Sneftel 13 years, 5 months ago
"Input Managers" are something that I see are commonly discussed in this forum, to a create extent in this thread. However, I typically see only keyboard events discussed and not mouse inputs such as x/y movement, scrolling and extra buttons (such as thumb buttons like Mouse5). I am trying to venture away from always using DirectX input to handle keyboard/mouse. Can anyone suggest a good way to set up handling input for mouse event, or even more ways to do keyboard events.

Any kind of explanation, or source code or tutorials would be very much appreciated.
Advertisement
Quote:I am trying to venture away from always using DirectX input..

Good idea.

Unless you run into a particular problem, just use window messages (WM_KEYDOWN, WM_MOUSEMOVE, WM_VSCROLL, etc.).

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

There is one issue that I can not grasp the concept of, and that is how "InputNotifiers" are used.

For example, I can see that typically when the "InputManager" detects that a key it pressed, it will send out a notifier. However, how is that notifier used? For example, is it attached to a class some how, or is an instance of it created and signed a function pointer it should call when a key is pressed?
I say forget about these fancy "notifier" "listener" fancy shit and the classes. Just make it work. Maybe with one nasty disgusting switch statement and globals and every evil things. Your next input handler will be much nicer.
An EventManager I wrote at one time maintained a vector of event/function pointer pairs. Events (with an accompanying callback function pointer) were registered (added to the vector) with the EventManager. On an event, the mgr iterated through the vector looking for requested events and calling the associated callback function.

I've never found a really good use for an event manager that complicated.

Similar to what szecs mentions, since then I just maintain a bunch of global booleans* for keystrokes of interest, and each object/class/function/etc. checks the globals as needed.

*E.g.,
case WM_KEYDOWN:   switch(LOWORD(wParam))   {      case VK_NUMPAD0: bNP0 = true; break;      case VK_NUMPAD1: bNP1 = true; break;// etc.case WM_KEYUP:   switch(LOWORD(wParam))   {      case VK_NUMPAD0: bNP0 = false; break;      case VK_NUMPAD1: bNP1 = false; break;// etc.

where bNP0, bNP1, bNP2, etc., are just global bools.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

I would to have my InputManager not deal with global variables.

Here is how I was going to set it up, first I create a class known as InputNotifier. This class will take in a key, a function pointer to a KeyDown function and a function pointer to a KeyUp function.

	#define INFUNCPTR(name) void (GameObject::*name)()	class InputNotifier	{	protected:		InputKey m_Key;		INFUNCPTR(m_OnKeyUp);		INFUNCPTR(m_OnKeyDown);	public:		InputNotifier(InputKey key, INFUNCPTR(onKeyUp), INFUNCPTR(onKeyDown))		{			key = key;			m_OnKeyUp = onKeyUp;			m_OnKeyDown = onKeyDown;		}		virtual ~InputNotifier() { }		virtual void OnKeyDown(LPARAM lParam)		{			m_OnKeyUp;		}		virtual void OnKeyUp(LPARAM lParam)		{			m_OnKeyDown;		}		InputKey GetKey() const { return m_Key; }	};


The second thing I would do is create a manager, to use with WinProc

	class InputManager	{	protected:		vector<InputNotifier *> m_InputListeners;	public:		InputManager();		virtual ~InputManager();		bool AddListener(InputKey key, INFUNCPTR(onKeyUp), INFUNCPTR(onKeyDown));		void OnKeyDown(WPARAM wParam, LPARAM lParam);		void OnKeyUp(WPARAM wParam, LPARAM lParam);	};


The problem I am having is how do I hook in a function that would deal with objects that update based upon time? For example, I want my W key to move my camera up a little but, but that would require the current time slice, or approaching time slice.

Possible Fix 1: (Hack)
In could fix this by storing the last time slice, then use that when I press the W key ... but this seems like a hack.

Possible Fix 2: (Hackish).
In my message manager I store a queue of messages that require the time slice to be added in. The problem with doing this is that it would be a seperate list of messages to all of my other messages, meaning they may not get executed in order ... this could be very dangerous.

Does anyone have any suggestions on how this may be done?
Quote:I want my W key to move my camera up a little..

It's not very clear what problem you're trying to solve.

I would think, if the camera updates at some delta time, and W is down, move the camera at some speed times the delta time, regardless of when the key was pressed. Are you concerned that there will be some conflict (it's not clear) if the key was pressed just before the update so it really wasn't down for the entire delta time? Are your update times so long that it would make a difference?

Maybe a bit more explanation would help.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Sorry about that, basically, I want to some how communicate to an object (my camera) that W has been pressed so it can preform a certain function.

The problem I am having is syncing up input with my update loop.

The way I use to have my update look when the input manager was not done through WndProc but rather DirectX was basically like this ...

------ Main Engine Update

float dt = gameTimer.fromLastUpdate()

if ( InputManager.buttonPressed(w) == true)
camera.moveForward(dt);

etc ...
------

Now, I am no longer checking to see if the button was pressed in the Main Engine update and I am not sure how to properly attach Input Notifiers to events (or actions).

Now, I could simply do the same thing, not use InputNotifier and queue all the inputs that are made into InputManager. However, I would like to process through the InputManagers keys pressed as they were pressed. For example, with the above approach you check things in order of however your if's end us using it. I would like to process my inputs in the order they happen.

I was talking about nasty code, but you have to have a structure: decouple keyboard handling from the logic, if it's not event triggered.

I mean, if there's an event based action, put it into the keyboard handler, but if it's a regularly updated stuff: decouple.

I you want a certain time between the event handling (for example you waqnt to queue key-presses for a snake game), then I'd make my own keyboard queue, but only for the certain keys.


So in your example, I would use (non queued)
//updatefloat dt = gameTimer.fromLastUpdate()if (MoveState.forward == TRUE )camera.moveForward(dt);...//event handling:WM_KEYDOWN:case 'W':     MoveState.forward = TRUE;     InputManager.buttonPressed = TRUE;     break;... // of course, use the OPP like setter/getters whatever


queued
...//event handling:WM_KEYDOWN:case 'W': case 'S': // and other keys you want buffed     CommandQueue.push(wParam);     break;//updatefloat dt = gameTimer.fromLastUpdate()...if ( time_passed_since_the_last_command_execution) // **sigh, I've just woken up )ExecuteCommand(CommandQueue.pop());
Hmm, interesting ... so on your queue example you don't even use a listener at all do you?

This topic is closed to new replies.

Advertisement