• Advertisement
Sign in to follow this  

Unity Handling keyboard/mouse input

This topic is 2650 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

"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.

Share this post


Link to post
Share on other sites
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.).

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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)
//update
float 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;

//update

float dt = gameTimer.fromLastUpdate()

...if ( time_passed_since_the_last_command_execution) // **sigh, I've just woken up )
ExecuteCommand(CommandQueue.pop());

Share this post


Link to post
Share on other sites
Hmm, interesting ... so on your queue example you don't even use a listener at all do you?

Share this post


Link to post
Share on other sites
Quote:
Original post by Hurp
Hmm, interesting ... so on your queue example you don't even use a listener at all do you?


I don't even know what listener is. And I have made many inputs of many kinds before.


@NumberXaero:
If the logic/behaviour requires this special kind of input handling. For example command queue, when the commands are executed in sequence, and there's a small time between these executions. Or the execution is executed only if a certain condition is true (so it cannot be executed the same time the event input occurs).
I hope that's clear.

Share this post


Link to post
Share on other sites
I dont know, seems over complicated. For me you have two cases, 1, you want things to execute at time of key press, ie feed some gui text box string. 2, you want continuous state of the current device, be it mouse or keyboard, and you check for a given state change each update, ie camera, you move as long as the key is down, and stop when the key goes up. Time of event is passed along in case 1, time of state change can be checked in case 2. Build state for each device and each key/button

- OnInput
-- Event received, up or down
-- Update device state (key/button)
-- Fire code that executes once, on up or down

// Device state is now current
- OnFrameUpdate
-- Pass state around
-- Fire code that executes continuously (character movement)

Im using something similar for what could become a very complex character movement that needs to know if key/button isDown, isUp, isFirstDown, isFirstUp, and the time involved with each, how long has it been down? how long has it been up? the time of first down? the time the key was released? and its worked well so far.

Share this post


Link to post
Share on other sites
I just noticed that if are looking for WM_KEYDOWN and you press two buttons (such as "W" and "S") it will only send the input message for the last key you press, even if you are holding both. IS there any way to get the message for every button you are pressing?

Share this post


Link to post
Share on other sites
Quote:
Original post by NumberXaero
I dont know, seems over complicated. For me you have two cases, 1, you want things to execute at time of key press, ie feed some gui text box string. 2, you want continuous state of the current device, be it mouse or keyboard, and you check for a given state change each update, ie camera, you move as long as the key is down, and stop when the key goes up. Time of event is passed along in case 1, time of state change can be checked in case 2. Build state for each device and each key/button


If you haven't used other methods it doesn't mean there's can't be a need for others. It's not about being complicated, it's about the BEHAVIOUR you want. I guess I wasn't clear in my previous post, I won't try to explain again.

Share this post


Link to post
Share on other sites
Quote:


Quote:

Original post by NumberXaero
I dont know, seems over complicated. For me you have two cases, 1, you want things to execute at time of key press, ie feed some gui text box string. 2, you want continuous state of the current device, be it mouse or keyboard, and you check for a given state change each update, ie camera, you move as long as the key is down, and stop when the key goes up. Time of event is passed along in case 1, time of state change can be checked in case 2. Build state for each device and each key/button


If you haven't used other methods it doesn't mean there's can't be a need for others. It's not about being complicated, it's about the BEHAVIOUR you want. I guess I wasn't clear in my previous post, I won't try to explain again.


Fine, your method is better, you win. It wasnt an attack, just a suggestion that queues to emulate what he was doing previously might be overkill and change things more then he wants.

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


Quote:
Hurp:
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).


So I suggested tracking the state of all buttons and keys and updating their state when input is received. After that you can fire event handlers that want to know about up/down events as they happen, and still check the state each frame as though you were checking directx during update.

Share this post


Link to post
Share on other sites
My main issue I am having right now is that I want messages to pump when I am holding down two buttons, with WM_KEYDOWN it only sends one (the latest).

I was going to move to using WM_INPUT, however, this thread recommends that I do not. I do not fully understand why it is a bad idea to use WM_INPUT though. Could anyone share some insight on this?

Share this post


Link to post
Share on other sites
The thread never recommends against raw input. It just describes its behavior, which the poster thought was wrong.

One of the threads linked to within the thread you posted mentions exactly what I was talking about. The users problem is that hes basically tracking actions, key down/up when they happen, what you want to be tracking is state of each key, which you must maintain on your own. Use raw input to get direct up and down events, store these per key in an array of key states somewhere. When you need to you can check against this managed keyboard state and perform your logic based on whats up and down as combinations of keys if need be. When WM_INPUT is received, simply store the time it happened, when you get key up, check the time again, and determine how long it was down by using the time you stored on first down. There should be very little you cant do maintaining the entire state of each key and the time everything happened.

Storing your own state per key means you dont need explicit messages pumped from raw input, you just need to know that things go down, and they go up because you are essentially recording everything thing that is happening while the app runs.

Share this post


Link to post
Share on other sites
Using WM_INPUT I am still unable to detect two keys simutanously being pressed. Here is what I will do

Press W and hold it :: Doing this will flood my Output window about it being pressed.

While still holding W, I press A and hold it. I am now holding W AND A. However, it is only detecting that A is being pressed. I can tell this by the fact that I am only seeing messages in my output about A being pressed.

Here is my code, does anyone know what I may be doing wrong?

WM_INPUT
{
UINT dwSize;

GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize,
sizeof(RAWINPUTHEADER));
LPBYTE lpb = new BYTE[dwSize];
if (lpb == NULL)
{
return 0;
}

if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize )
OutputDebugString (TEXT("GetRawInputData doesn't return correct size !\n"));

RAWINPUT* raw = (RAWINPUT*)lpb;

char szTempOutput[512];
HRESULT hResult;

if(raw->data.keyboard.Message == 0x0100)
{
hResult = StringCchPrintf(szTempOutput, STRSAFE_MAX_CCH, TEXT(" Kbd: DOWN VK=%04x \n"),
raw->data.keyboard.VKey);

OutputDebugString(szTempOutput);
}
if(raw->data.keyboard.Message == 0x0101)
{
hResult = StringCchPrintf(szTempOutput, STRSAFE_MAX_CCH, TEXT(" Kbd: UP VK=%04x \n"),
raw->data.keyboard.VKey);

OutputDebugString(szTempOutput);
}
delete[] lpb;
return 0;

}
break;

Share this post


Link to post
Share on other sites
It will be able to detect that W was released, here is my log

Kbd: DOWN VK=0057 // Press and hold W
Kbd: DOWN VK=0057
Kbd: DOWN VK=0057
Kbd: DOWN VK=0057
Kbd: DOWN VK=0041 // Press A and hold A, while still holding W
Kbd: DOWN VK=0041
Kbd: DOWN VK=0041
Kbd: UP VK=0057 // Release W, while still holding A
Kbd: DOWN VK=0041
Kbd: DOWN VK=0041
Kbd: UP VK=0041 // Release A

Share this post


Link to post
Share on other sites
Now store the state of that key, you know when it goes down, and you can assume its still down because you havent received an up message. Once youve stored it, it can be passed around to any place that needs to know if a keys down or up. This also allow for key combos to be checked for, because you have the state of all keys up to date at all times. Or you can use event handlers of some kind, and have the listeners, notifiers, observers, w/e, execute directly when down and up messages are received.

Share this post


Link to post
Share on other sites
I could basically do the same thin with WM_KEYDOWN and WM_KEYUP, I don't see how using WM_INPUT adds an advantage ... how does it?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By GytisDev
      Hello,
      without going into any details I am looking for any articles or blogs or advice about city building and RTS games in general. I tried to search for these on my own, but would like to see your input also. I want to make a very simple version of a game like Banished or Kingdoms and Castles,  where I would be able to place like two types of buildings, make farms and cut trees for resources while controlling a single worker. I have some problem understanding how these games works in the back-end: how various data can be stored about the map and objects, how grids works, implementing work system (like a little cube (human) walks to a tree and cuts it) and so on. I am also pretty confident in my programming capabilities for such a game. Sorry if I make any mistakes, English is not my native language.
      Thank you in advance.
    • By Ovicior
      Hey,
      So I'm currently working on a rogue-like top-down game that features melee combat. Getting basic weapon stats like power, weight, and range is not a problem. I am, however, having a problem with coming up with a flexible and dynamic system to allow me to quickly create unique effects for the weapons. I want to essentially create a sort of API that is called when appropriate and gives whatever information is necessary (For example, I could opt to use methods called OnPlayerHit() or IfPlayerBleeding() to implement behavior for each weapon). The issue is, I've never actually made a system as flexible as this.
      My current idea is to make a base abstract weapon class, and then have calls to all the methods when appropriate in there (OnPlayerHit() would be called whenever the player's health is subtracted from, for example). This would involve creating a sub-class for every weapon type and overriding each method to make sure the behavior works appropriately. This does not feel very efficient or clean at all. I was thinking of using interfaces to allow for the implementation of whatever "event" is needed (such as having an interface for OnPlayerAttack(), which would force the creation of a method that is called whenever the player attacks something).
       
      Here's a couple unique weapon ideas I have:
      Explosion sword: Create explosion in attack direction.
      Cold sword: Chance to freeze enemies when they are hit.
      Electric sword: On attack, electricity chains damage to nearby enemies.
       
      I'm basically trying to create a sort of API that'll allow me to easily inherit from a base weapon class and add additional behaviors somehow. One thing to know is that I'm on Unity, and swapping the weapon object's weapon component whenever the weapon changes is not at all a good idea. I need some way to contain all this varying data in one Unity component that can contain a Weapon field to hold all this data. Any ideas?
       
      I'm currently considering having a WeaponController class that can contain a Weapon class, which calls all the methods I use to create unique effects in the weapon (Such as OnPlayerAttack()) when appropriate.
    • By Vu Chi Thien
      Hi fellow game devs,
      First, I would like to apologize for the wall of text.
      As you may notice I have been digging in vehicle simulation for some times now through my clutch question posts. And thanks to the generous help of you guys, especially @CombatWombat I have finished my clutch model (Really CombatWombat you deserve much more than a post upvote, I would buy you a drink if I could ha ha). 
      Now the final piece in my vehicle physic model is the differential. For now I have an open-differential model working quite well by just outputting torque 50-50 to left and right wheel. Now I would like to implement a Limited Slip Differential. I have very limited knowledge about LSD, and what I know about LSD is through readings on racer.nl documentation, watching Youtube videos, and playing around with games like Assetto Corsa and Project Cars. So this is what I understand so far:
      - The LSD acts like an open-diff when there is no torque from engine applied to the input shaft of the diff. However, in clutch-type LSD there is still an amount of binding between the left and right wheel due to preload spring.
      - When there is torque to the input shaft (on power and off power in 2 ways LSD), in ramp LSD, the ramp will push the clutch patch together, creating binding force. The amount of binding force depends on the amount of clutch patch and ramp angle, so the diff will not completely locked up and there is still difference in wheel speed between left and right wheel, but when the locking force is enough the diff will lock.
      - There also something I'm not sure is the amount of torque ratio based on road resistance torque (rolling resistance I guess)., but since I cannot extract rolling resistance from the tire model I'm using (Unity wheelCollider), I think I would not use this approach. Instead I'm going to use the speed difference in left and right wheel, similar to torsen diff. Below is my rough model with the clutch type LSD:
      speedDiff = leftWheelSpeed - rightWheelSpeed; //torque to differential input shaft. //first treat the diff as an open diff with equal torque to both wheels inputTorque = gearBoxTorque * 0.5f; //then modify torque to each wheel based on wheel speed difference //the difference in torque depends on speed difference, throttleInput (on/off power) //amount of locking force wanted at different amount of speed difference, //and preload force //torque to left wheel leftWheelTorque = inputTorque - (speedDiff * preLoadForce + lockingForce * throttleInput); //torque to right wheel rightWheelTorque = inputTorque + (speedDiff * preLoadForce + lockingForce * throttleInput); I'm putting throttle input in because from what I've read the amount of locking also depends on the amount of throttle input (harder throttle -> higher  torque input -> stronger locking). The model is nowhere near good, so please jump in and correct me.
      Also I have a few questions:
      - In torsen/geared LSD, is it correct that the diff actually never lock but only split torque based on bias ratio, which also based on speed difference between wheels? And does the bias only happen when the speed difference reaches the ratio (say 2:1 or 3:1) and below that it will act like an open diff, which basically like an open diff with an if statement to switch state?
      - Is it correct that the amount of locking force in clutch LSD depends on amount of input torque? If so, what is the threshold of the input torque to "activate" the diff (start splitting torque)? How can I get the amount of torque bias ratio (in wheelTorque = inputTorque * biasRatio) based on the speed difference or rolling resistance at wheel?
      - Is the speed at the input shaft of the diff always equals to the average speed of 2 wheels ie (left + right) / 2?
      Please help me out with this. I haven't found any topic about this yet on gamedev, and this is my final piece of the puzzle. Thank you guys very very much.
    • By Estra
      Memory Trees is a PC game and Life+Farming simulation game. Harvest Moon and Rune Factory , the game will be quite big. I believe that this will take a long time to finish
      Looking for
      Programmer
      1 experience using Unity/C++
      2 have a portfolio of Programmer
      3 like RPG game ( Rune rune factory / zelda series / FF series )
      4 Have responsibility + Time Management
      and friendly easy working with others Programmer willing to use Skype for communication with team please E-mail me if you're interested
      Split %: Revenue share. We can discuss. Fully Funded servers and contents
      and friendly easy working with others willing to use Skype for communication with team please E-mail me if you're interested
      we can talk more detail in Estherfanworld@gmail.com Don't comment here
      Thank you so much for reading
      More about our game
      Memory Trees : forget me not

      Thank you so much for reading
      Ps.Please make sure that you have unity skill and Have responsibility + Time Management,
      because If not it will waste time not one but both of us
       

  • Advertisement