- Home /
Any way to key JUST keydown and JUST keyup events?
I'm trying to determine when keys are really going down and really going up. They Event stuff of course has these events, but, as it says in the docs for KeyDown:
"This event is sent repeatedly depending on the end user's keyboard repeat settings."
So I'm getting a whole slew of 'keydown' events, just by holding a key down. This is false for my purposes, because the key is already down.
I could make an array to hold key up/down status for all keys, then have it ignore key-down events until it sees a key-up for each key.
Is there an easier way?
Late Update: It's buggy too, so best option at this point is a hybrid, see http://answers.unity3d.com/questions/51293/mac-keys-not-showing-up-or-very-strangely
I don't know if this'd work... But, can you get the key down, but also if the key isn't just get down? If that makes sense... I don't know if that'd work... You'd have to test it, sorry =/... But good question imo.
Thanks, not sure what you mean though. I really need to monitor the whole keyboard, and I'm trying to avoid testing each and every key explicitly.
Am i right in assu$$anonymous$$g that if you changed the options on your keyboard to single press events and not press/hold that you would achieve the effect you want? eg in a word document if you hold a key 11111111111111 it repeats, with your change of settings it would only do it once no matter how long you held it down? Some of the answers here seem to mislead my understanding of the question. Seriously though, you're a pro and there are only a few people who have a higher rep than you, answers to your knowledge-filled question are hard to come by.
Thanks. Yes, I don't ask questions lightly. Yes, my computer is set to repeat, but I can't change that on everyone's machine. I was hoping there was another option (like Update/Get$$anonymous$$eyDown, but more like GetAny$$anonymous$$eyDown with a parameter telling which key went down, or some option to set like 'Input.autoRepeat = false')
Answer by Bunny83 · Apr 28, 2011 at 01:24 AM
edit
Since the links i posted don't work anymore (even the question id has changed, probably happend when UA switched to qato) here's a working solution which is pretty straight forward ;)
// C#
void OnGUI()
{
Event e = Event.current;
if (e.type == EventType.KeyDown)
{
if (Input.GetKeyDown(e.keyCode))
{
Debug.Log("Down: " + e.keyCode);
}
}
if (e.type == EventType.KeyDown)
{
Debug.Log("Up: " + e.keyCode);
}
}
You can't prevent the KeyDown event from happening at the systems repeat rate. Even on windows you'll get a WM_KEYDOWN for each repeated key. However the message contains a bit-flag if the key was down previously. Unfortunately this information isn't transferred into the Event system.
However in combination with Input.GetKeyDown you can easily filter out the repeated events.
Hey @Bunny83. As usual you save the day :P Thanks for your advice on writing my own Icon loader (converting .ICO to .PNG) I guess that's the way it should be done.
On another note regarding this question here, your answer emphasized that currently the best way to detect $$anonymous$$B input is through Event.keyCode... Because using Input.Get$$anonymous$$ey and its variations in Update() proved to be unworthy since it merely checks for input flags each FRA$$anonymous$$E only (doesn't detect the button being pressed the moment it's actually pressed).
I could use what you used in OnGUI and implement a switch statement on e.type to handle different case ($$anonymous$$eyDown, $$anonymous$$eyUp etc..) BUT I am trying to do this using uGUI
I have been poking around for implementing this logic in uGUI but so far there's ISubmitHandler which works for submit key only, and IUpdateSelectedHandler which seems to be a candidate superhero: Example from uGUI's InputField source code
Though I have no idea how this would happen. If you could shed some light on using OnUpdateSelected for keyboard input detection I would be REALLY glad. Because without this I would actually have to use deprecated OnGUI with uGUI lol
@$$anonymous$$ajor0: Sorry for the late reply, i wasn't home the last two weeks ^^.
I think you have a wrong view on how things actually work in Unity ^^. The scripting environment in Unity runs on a single thread, the main thread. So everything happens in a successive fashion. There's no "in-between" event, ever.
Even in a "normal" windows application (actually a unity windows standalone build is such an application) you don't get in between events. A windows application has a message queue. The system will generate and queue messages into that queue. The application has to poll the queue at some point in the main loop to actually read those messages. This is called the message pump as it usually just calls Peek$$anonymous$$essage / Get$$anonymous$$essage and pass the information to the proper handler.
Unity actually works exactly the same way. At the start of the main look Unity will process the systems message queue and create it's own "message" type for each event. That "message" is a Event in Unity. So Unity just copies over the system events into it's own queue at the start of a frame. This queue is processed automatically and will call OnGUI for each Event in the queue.
In the past OnGUI was the only way to access those events. However since the new GUI system the Event class has a new static method called PopEvent. This method can be used to manually poll and remove a queued event from the queue. All you have to do is create a variable of type "Event" and initialize it with an empty new Event()
. When you call PopEvent and passing your empty event instance, the method will copy the information of the next queued event into your variable and remove the event from the queue. If the method returns true it successfully read an event. If it returns false the queue is empty.
PopEvent has one big disadvantage over OnGUI: There can only be one script that uses a PopEvent loop as it removes the Events from the queue. OnGUI can be processed by multiple script.
The third-party framework NGUI actually used OnGUI to read the keyboard events. As you can see in the code you've linked above the new GUI system uses a PopEvent loop. Of course a GUI system usually only has one active element which will receive all system events so that's usually not a problem.
Anyways, you won't get a better response time using OnGUI or PopEvent. All input is still gathered at the beginning of a frame and that information will be constant during that frame. If during a frame new events happens, it won't be visible until the next frame after Unity has read it's own message queue and make it available to it's own event system.
In a frame-driven system you don't want self-changing states during a frame.
@Bunny83 Thank you so much for the beautifully elaborated description on how Unity handles events! Gotta love exploring low-level concepts and how things work in the background!
Using PopEvent()
sadly prevented other uGUI components from taking Input as you said since it pops the event from the queue. This is not a big problem since I have a hasFocus
flag so it's not like I am popping the event from the EventQueue every frame -- just when the focus is on my custom uGUI element. Nevertheless, I reverted back to OnGUI and things are going quite well now!
Wish I could transform your comment into an answer to my question here but unfortunately that is not possible. So if you are not going to copy-paste your answer there in the following days (cuz I want you to take the credit for it) then I am going to do it myself and mention your name there :)
Answer by Matthew 5 · Mar 31, 2011 at 12:02 AM
var KeyDown:boolean = false;
function Update () { if (Input.GetKeyDown("c")) {
(if !KeyDown) {
doSomething
KeyDown = true; //turns off the loop
}
if (Input.GetKeyUp("c")) {
(if KeyDown) {
doSomething
KeyDown = flase; //turns off the loop.. again
}
}
That is a quick work around..
though.. once you trigger the false statement; it will stop the lines of 'doSomething' .. so make a method and in that method, after it does what it needs todo, add $$anonymous$$eyDown = true;
Yeah, this is basically what I meant, but since I need to monitor all keys, I'd have to have an array of $$anonymous$$eyDown to check thus. I'm going ahead with that unless/until something simpler comes along. I'll vote for an option on the feedback forum (like that will ever happen!)
Goodluck man, is there any way you can go about fixing your keyboard issue, Get$$anonymous$$eyDown should only fire on one frame.
Otherwise, Im glad this helped and accept an answer so people can see its been solved.
$$anonymous$$atty
Answer by miketucker · Sep 04, 2013 at 01:11 PM
here is a more elegant solution:
void OnGUI()
{
Event e = Event.current;
if (e.isKey && e.type == EventType.KeyUp){
switch(e.keyCode){
case KeyCode.Space: Debug(); break;
case KeyCode.UpArrow: ShiftUp(); break;
}
}
}
Answer by Qwerty · Mar 31, 2011 at 12:04 AM
Hey,
You can use :
if(Input.GetKeyDown("c")){ //do stuff }
if(Input.GetKeyUp("c")){ //do stuff }
Even better though, you can use axes if these are game controls (especially if used constantly) with Edit > Project Settings > Input Then:
Input.GetAxis("AxisName")
And when all else fails (which it should not here), you can always result to good old true or false (or as I like 1=true , 0=false) such as:
//Your trigger happens: ItsGoing = 1;
if(ItsGoing == 1){ //Only do this when its 1, then reset back to 0 ItsGoing = 0; }
Hope this helps!
The problem he was having is that his PC sends $$anonymous$$eyDown every frame due to his PC setup, unlike normally it would only send on the first frame it happens.
ooh, now I understand. yes he will need to use some kind of true false system then like you suggested under this.
Answer by AngryOldMan · Mar 31, 2011 at 03:09 AM
i think what mattyk means is
var KeyDown:boolean = false;
function Update () { if (Input.GetKeyDown("y")) { if (KeyDown == false) { Debug.Log ("Key is being pressed"); KeyDown = true; } }
if (Input.GetKeyUp("y"))
{
Debug.Log ("Key has been unpressed");
KeyDown = false;
}
}
but like you mentioned this will have to be specified for each key giving you possibly 20-30 variables and copies of this script, which doesnt sound like a day of fun making. I'l be watching via favorites to see if you get a hardcode solution.