- Home /
Unable to catch KeyCode.LeftShift Down AND Up
Hey everyone.
This maybe something stupid in the end but I have spent several days trying to find a solution to this problem and have come up with nothing at all. Every search yields results for Input.GetKeyDown(KeyCode.LeftShift)
, which appears to work just fine, but I can find no information about why Input.GetKeyUp(KeyCode.LeftShift)
simply does not appear to work .
Here is my experimental Update function
void Update () {
bool isShiftKeyDown = false;
if( Input.GetKeyDown(KeyCode.LeftShift) ){ isShiftKeyDown = true; }
else if( Input.GetKeyUp(KeyCode.LeftShift) ){ isShiftKeyDown = false; }
Debug.Log(isShiftKeyDown);
}
At this stage I have tried many, many permutations of this code with the same results: isShiftKeyDown will be false until I press the Shift key, at which point it changes to true as expected. However, releasing the key seems to do nothing.
Bizarrely it will work if I only try to catch Input.GetKeyUp
, or even reverse the order of the Up/Down checks, but in either case the second check is never fired. I have now spent so long on this simple problem that I am no longer sure what is going on and I'm half convinced that I'm doing something strange, but there is nothing else in the project, just this code dropped on an empty game object.
Can anyone suggest how I can get the shift key to toggle the boolean using up and down key presses?
BTW: I have of course tried removing the GetKeyUpand
just putting an Else
in its place. No difference.
Update Okay. So. Lots of discussion going on.
The boolean in the Update function: Yes, I know. I put it there just to show what was going on. I tried with it, without it, no difference.
However...
Having tried this code (and many permutations of it) in multiple projects, all with the same quite bizarre results I have now re-installed Unity (2018 again) and re-loaded 3 of those projects in turn, and in every single case the code works as expected!
I have no ideas or answers for this. To my knowledge every other aspect of Unity seemed to be fine, with this strange exception, caused only because I wanted to use the shift key! I have now checked 3 projects that previously failed, and created another two fresh ones, and everything works fine.
Not sure what to say about this.
Update (Again)
Okay, so. I uninstalled Unity entirely and re-installed (Still the latest version), and I have now been using it for development (rather than just projects to test code) and so far everything has continued to work fine.
Bunny83
Yes, I understand what GetKeyDown and GetKeyUp actually do, thanks, and as already mentioned I am fully aware that the bool is in Update in the code above. Perhaps you should not post an answer when you don't answer the question. If you have a comment it may be an idea to use the comment function.
@JVene
I'm still not sure why this problem occurred and have now tried many permutations of the debug code in order to catch changes without running Debug.Log in the Update (Yes, it does slow things down quite considerably) and I consistently got the same strange results.
Yes, Sticky keys. Hideous thing but we have to live with it. I have it disabled entirely (Holding any of those keys does not 'do' anything) and if it does trigger it makes an unpleasant noise so I think we can rule that out.
As for the OS and the queued button presses, I agree that this could cause a problem, however that does not explain why identical code (the same test projects) now work in a fresh installation of Unity, so I suspect that something, somewhere along the line got broken or corrupted in the Unity installation.
I cant see what could have had such a bizarre effect on Unity, but in any case this problem appears to be resolved, although without any satisfactory answer.
Many thanks to all who contributed ideas. A re-install of Unity fixed it, I just wish we had a concrete reason for the problem in the first place.
Have you debugged that code? For me it looks like it should work. How do you tell that the second condition never happens? $$anonymous$$aybe you have collapsed Console window? Try putting different Debug.Log on every if/elseif statement.
Console window is fine and I use Debug.Log to check values
I've checked with the above code, and for me it seems to work fine: the frame I press the left shift, it prints true
, in the rest of the frames it prints false
. Is that what you expect it to do?
Then I also tested with this code:
public enum $$anonymous$$eyState { UNPRESSED, DOWN, PRESSED, UP };
[SerializeField] private $$anonymous$$eyState leftShiftState = $$anonymous$$eyState.UNPRESSED;
private void Update () {
switch (leftShiftState) {
case $$anonymous$$eyState.DOWN: leftShiftState = $$anonymous$$eyState.PRESSED; break;
case $$anonymous$$eyState.UP: leftShiftState = $$anonymous$$eyState.UNPRESSED; break;
}
if (Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.LeftShift)) { leftShiftState = $$anonymous$$eyState.DOWN; }
else if (Input.Get$$anonymous$$eyUp($$anonymous$$eyCode.LeftShift)) { leftShiftState = $$anonymous$$eyState.UP; }
Debug.Log(leftShiftState);
}
This also works correctly in my opinion, UNPRESSED in the beginning, DOWN for one frame, PRESSED until I release the key, then it is UP for one frame, and then returns to UNPRESSED.
If this is not what you experience, that is quite bizarre. Some weird and maybe stupid questions: - are you sure there is nothing else in the project affecting input?
- when you press the key, is the Game view in focus? (when I clicked on the Console, for a moment thought I reproduced the issue, but then I realised that it's simply not in focus)
- what version of Unity are you on? (Unity 2018 is introducing a new input system, but it might be buggy)
- does maybe your OS override keyboard events? - have you tried with a different keyboard? It might be a hardware error
These are all the possible reasons that come to my $$anonymous$$d (I think your code is correct, the issue is something else).
You are correct in your assessment of what I want to happen, however, it seems that for some reason it does not. Thanks for letting me know that the code should work.
Annoyingly the code you posted works just fine and does what I was expecting, however, that does not explain while the original code (still) does not work. I have now tried this in multiple new projects and the code you posted always works and the code I posted originally does not.
BTW this is Unity 2018 on Windows 10 (64) and your comment about the new input system and possible bugs is noted. I'm going to uninstall Unity entirely and re-install before trying again and regardless of the results I will likely open a bug report.
Thanks for your effort, and for confir$$anonymous$$g that my code should work - at least I know I'm not going mad!
It's fun that just after I add this code first time it's not working, but after restarting/resaving script it works well.
I think that you already tried it, but you need to be in "game" window as active, to test it.
Thanks for the update @$$anonymous$$axVon$$anonymous$$ , I'm glad that now it works, but I share your frustration about not knowing what caused the problem!
Good luck!
Answer by Bunny83 · Aug 01, 2018 at 01:02 PM
There is way to much disussion going on here. Your original code in the question doesn't make any sense since you delcared your boolean inside Update. So it doesn't keep it's state between two update calls.
I'm not sure if you understand what GetKeyDown and GetKeyUp actually does. They return true for one frame when the key is pressed or released. So both methods do always return false in the idle case. When the button is pressed down GetKeyDown will return true for one frame only. So while holding down the button both methods will return false again. When you release the button GetKeyUp will return true for one frame. So the next frame both will return false again.
On the other hand "GetKey" will return true while the key is down and will return false while the key is not pressed / not held down.
If you think there's any kind of issue, first come up with a test case that does make sense. Second make sure you understand what should happen. Basic code analysis. If you don't understand what should happen it's pointless to speculate about half-baked observations. So you should write down what you think is the expected behaviour based on the code and then compare the result you've observed with what you have expected. In most cases you either looked at the wrong things and got to the wrong conclusions or you expectations were wrong. In very rare cases there might be some kind of issue (could be hardware or OS dependent).
Anyways I've tested the corrected code of The_Icaruz and it works exactly as expected. Make sure you don't have collapse enabled in your console. This is the root of many false conclusions.
.
Please do not post an answer when you don't answer the question. If you have an update on your question / issue, just edit and extend your question.
Answer by The_Icaruz · Aug 01, 2018 at 09:03 AM
Hey am I missing something or why is the bool
in the Update ()
function.
If I'm not wrong the bool is set every frame to false
.
Maybe try something like :
bool isShiftKeyDown = false;
void Update ()
{
if( Input.GetKeyDown(KeyCode.LeftShift) )
{
isShiftKeyDown = true;
Debug.Log("ShiftKey is Down");
}
else if( Input.GetKeyUp(KeyCode.LeftShift) )
{
isShiftKeyDown = false;
Debug.Log("ShiftKey is Up");
}
}
Just checked your code: Shift goes down, shift comes up, shift never does anything again.
No offense, but this won't compile: isShif$$anonymous$$eyDown
is a local variable to Start()
, so it does not exist in the context of Update()
.
Apart from that, the issue is not with the code, it should work correctly, there must be a different reason.
Sorry I wasn't really thinking, now that you mentioned it you are right. Sorry for the wrong information.
While it is true that the code wouldn't compile (he even missed the quotes in the debug.log messages) the point he made is valid. If you declare the variable inside Update the variable won't keep its value between two frames. So the variable will only be true for one frame.
I've edited the answer and moved the variable declaration to class level and correctly put the messages in quotes. When i run the code i get the down and up messages correctly
If I add
if (isShift$$anonymous$$eyDown)
{
Debug.Log("Lshift is held down");
}
at the end of Update i get this log every frame as long as i hold down the left shift button. However this could be tested more easily by just doing
if (Input.Get$$anonymous$$ey($$anonymous$$eyCode.LeftShift))
Since that will return the current state of the button.
Answer by kalsut1 · Aug 01, 2018 at 08:18 AM
im somewhat new to coding but i think whats happening is that because you are using an if statement and then an else statement it isnt getting the else because at the same time it finds that the key isnt down then it goes gets if the key is up so it is checking slightly late. try putting the two in completely different if statements instead of an if else if and let me know if that works.
Nope, no difference. Already tried that and did it again (just in case) a few seconds ago.
No, that cannot cause this issue, the value of Input.Get$$anonymous$$eyDown()
and Input.Get$$anonymous$$eyUp()
does not change within the same frame. That could happen if the input system were updating on a separate thread at the same time, but the main loop of Unity is single-threaded (in my experience).
Answer by AShenawy · Aug 01, 2018 at 11:11 AM
This has to be one of the strangest I've come across so far. I wrote the code as follows:
public class ShiftTester : MonoBehaviour
{
bool isShiftPressed = false;
void Update ()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
isShiftPressed = true;
if (Input.GetKeyUp(KeyCode.LeftShift))
isShiftPressed = false;
Debug.Log("Is Shift Pressed? " + isShiftPressed);
}
}
It worked absolutely fine as the debug switched between True and False. But as soon as I combined the 2 if
statements into an if
& else if
it stopped working and got stuck at True. I restarted Unity and Visual Studio, deleted the gameObject and made another script with the the original 2 ifs and nothing works now XD
UPDATE 1
This issue is somehow linked to setting up the bool in the beginning. I switched the initial declaration value to true instead of false and now it turns True when shift is pressed and when let go it turns False, then it's stuck at False.
UPDATE 2
The code works just fine. It's the Debug.Log
that was messing with our heads.
public class TestShift : MonoBehaviour
{
bool isShiftPressed = true;
void Update ()
{
if (Input.GetButtonDown("Shift"))
{
isShiftPressed = true;
Debug.Log("Is Shift Pressed? " + isShiftPressed);
}
else if (Input.GetButtonUp("Shift"))
{
isShiftPressed = false;
Debug.Log("Is Shift Pressed? " + isShiftPressed);
}
}
}
When logging each case it shows that it's actually reading and applying both inputs normally.
How??? I've just tested with your code, and it works correctly for me, no getting stuck! I don't doubt your test, I'm just very surprised that there can be such a difference!
What version of Unity do you use? What is the OS and editor for source code?
I just checked your reply and your version of code. I realised although you added the switch statement, its feed was still using the original if
& else if
statements like @$$anonymous$$axVon$$anonymous$$ did.
That's why I suspected the Debug.Log
itself and it turns out it was the issue all along messing with us. Now why the Log doesn't update is beyond my understanding.
I'm using Unity 2017.2.1f1 on Win7-64. But now this seems irrelevant.
Hmmm, in your second update you also changed the input method from Input.Get$$anonymous$$ey*()
to Input.GetButton*()
. That might make all the difference.
Either way, I've checked again with your code, and it works on 2017.3.1 as well (previously I checked on 2018.2.0).
I'm on Windows 10 64-bit, so maybe that is the difference? Also, I have a Pro license, but I really hope that does not influence input handling! :D
Answer by JVene · Aug 02, 2018 at 06:44 PM
@MaxVonK, I've read through and have a few points to offer that may shed light to the puzzles involved.
First, if the Debug log is handled by Unity through buffered streaming, it is possible that the output isn't flushed live. I have no data to prove this in the case of Unity, but in a career spanning decades I've had that hit me several times. It is unimportant, and other issues are important to consider. Writing out log data inside something running fast can actually interfere with the operation of the code. Use the debugger, or write test code which can reveal behavioral patterns, count and report after the fact to the log if you must, but live output to the debug log can change timing (more on that in a moment). Further, if you write output to debug at every update call, that could be streaming by at 60 entries per second. You might not even see a change in state, it could scroll off the display so fast you don't even see one entry that differs, and the alignment can be a bit of an optical illusion. Change output to produce a log entry when data has changed, not just every update call.
The first main point that strikes me is about Windows specifically. If you're on windows, the shift keys are handled by the operating system as a signal that "sticky keys" should be enabled, and that can kick in a dialog asking about that. It is related to accessibility features of Windows, and it can interfere with the count of keyup/keydown pairs in Windows regarding the shift, alt or ctl keys. Repeat this experiment on keys that don't involve these "sticky key" values to witness behavior without that potential interference from Windows.
A subscript to that point is about any multi-tasking operating system, as most in the modern era are. Applications may take focus of the keyboard at any time, and you might not even know it. Free AntiVirus packages, for example, pop up a dialog to offer some deal. Some poorly written ads like this can steal the keyboard for a moment, then return it. An update can launch a window, some applications may just take the focus - we have no idea what's going on outside the application we're writing. You can't depend on the notion that the keyboard always belongs to the application you're writing. The user can switch applications...lots of things happen which interfere with the assumption that all keystrokes come through your keyboard test routines.
As a result of that (and a great many other things), you must write defensively in this regard. As you'll see in a moment, you may not be able to absolutely rely on key up and key down, but may have to check key state instead.
The second main point is that there are times when a key up and a key down message are sent at the same time.
Read that again. I know some here may argue, but conduct an experiment on any key other than "specials" that the OS pays particular attention to, and you'll realize that Unity can and does on rare occasions send a key down and a key up to you in the very same update function call.
Keep in mind that what you're getting from key up and key down are queued information from what is ultimately a interrupt sending a message in real time. Update doesn't happen in real time, but happens in it's own cycle, so the input object (the event system in Unity) queues (remembers) what events have come in from the keyboard and forwards that accumulated data to you when requested. This is why it is even possible for the key up and key down to be sent simultaneously.
As a result, when the test is fashioned with an "else" clause as in the original example, it can happen that a key up has been received, but the corresponding key down will be ignored due to the else clause. There can be both awaiting this algorithm.
One could argue that the pending down would wait for the next update and still fire, but that assumes there is not an intervening key up in the meantime.
I conducted an experiment which merely counted the key ups and key downs on a few keys other than shift (shift keeps interrupting me with sticky requests on multiple tests), and counts the occasions that both fire true (simultaneous up and down in the same update).
On average I count 2 or 3 simultaneous key up/down cycles for about 20 to 30 tests in rapid fire on the key.
I did not see a failure of alignment to key up or down when there is no "else" clause skipping either test, but I did see a failure of alignment on the shift key in particular (there was not a 1 to 1 correspondence in the up count compared to the down count, I didn't get all up's from shift in particular). On non shift keys, I did not get an alignment failure, all downs had an up, but my experiment was a bit limited.
There is a chance, since this is queued data, and firing buttons can be hit rapidly, that if update is not firing at a good, regular rate (hint: garbage collection causes a hiccup), you could miss keyup/keydown pairs. Anything the OS does to you could also affect this.
If you were tracking the keyboard based on the raw interfaces, you would be able to know the state of the keyboard in a timing and a level beyond what Unity is forwarding to you. I don't see how C# can reach that level, so you are going to have to rely upon input.getkey.... calls to sense the state of the keyboard, but you can't rely on exact correspondence between down and up key calls. If you were getting COUNTS from input, you could, but they don't provide counts. Clearly, they don't count, they track state. When the OS intercepted the shift key for the sticky key dialog, Unity lost a keystroke.
Read that again to realize the OS can interfere with your sense of the keyboard, so you can't strictly rely on all key downs receiving a key up in all situations.
It might work 99.999999999999999999999% of the time, but not 100.0000%
You will get key ups. You can sense the current state of the keyboard (you're not going to get fake "stuck" keys this way). You just won't always get an up for every down.
Your answer
Follow this Question
Related Questions
What Key do you press to "Jump" in the T_T Tutorial? 2 Answers
Input.GetKeyDown doesn't work with several keys 1 Answer
How to get a key hold to do something which is stored in a variable as KeyCode ? 1 Answer
unbuffered keyboard input delay 2 Answers
iOS keyboard - limit number of keyboard characters 0 Answers