Search Unity

Find out which key was pressed.

Discussion in 'Scripting' started by Compressed, Feb 10, 2016.

  1. Compressed

    Compressed

    Joined:
    Sep 20, 2014
    Posts:
    59
    Hello, I am trying to find out which key the player pressed.
    So something like Input.inputString, except for all keys, not just for letters and numbers. So for example if the player presses F1 i want the key number, or some unique hash or something.

    And i'm NOT trying to find out if he pressed some specific key like R or something, i want to get the number (or something) of any key he pressed.

    Thanks
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    tranhuunghia23ngt and awsapps like this.
  3. Compressed

    Compressed

    Joined:
    Sep 20, 2014
    Posts:
    59
    Damn, that is pretty unfortunate. I tried it and the OnGui gets executed twice for every update and not only that, in half of them the keycode is returned as None even though i am holding the key down. Luckily i can work easily around that, but still it is pretty hacky and i can't believe they don't give us Input.keyCode
     
    technofeeliak likes this.
  4. roojerry

    roojerry

    Joined:
    Mar 18, 2013
    Posts:
    68
    Not efficient code, but, this will get you the current KeyCode pressed

    Code (CSharp):
    1. foreach(KeyCode kcode in Enum.GetValues(typeof(KeyCode)))
    2. {
    3.     if (Input.GetKey(kcode))
    4.         Debug.Log("KeyCode down: " + kcode);
    5. }
    EDIT: by "not efficient", I mean this should not be run within the game loop to detect input. There are 321 KeyCodes to loop through. If you were maybe doing user control remapping in an options menu, this could be useable. If we knew your use case, there may be a more elegant solution to what you are trying to do
     
    Last edited: Feb 10, 2016
    Powzone, wpetillo, astraR and 11 others like this.
  5. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Yeah I'd definitely not go that route.

    You'll probably have to combine it with checks to make sure the current event is actually a keyboard event
    Code (csharp):
    1.  
    2. void OnGUI()
    3. {
    4.     if (Event.current.isKey && Event.current.type == EventType.KeyDown)
    5.     {
    6.         Debug.Log(Event.current.keyCode);
    7.     }
    8. }
    9.  
     
    CYCLE-6, Rachan and ArcticPinou like this.
  6. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,624
    Actually, if you do some testing, looping through all the keycodes is far more efficient than the OnGUI route. Just having an OnGUI call in your scripts will cause memory allocations every frame which will eventually need to be collected by the garbage collector causing periodic slowdowns. Checking 321 keycodes takes next to no time in comparison.

    But do not get your keycode list every update. That will generate allocations as well. Call Enum.GetValues(typeof(KeyCode)) once on start and store those values for the duratiton.
     
  7. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Except there are keycodes that can map to the same key so you have the potential for multiple "true" scenarios. And you could pick up mouse/joystick events.

    I doubt this very much. How did you prove this and what's your definition of "far more efficient"? :)
     
  8. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    5,624
    Simply filter them out with your own keycode list that excludes these.

    From another post of mine from last year:

    Just for fun I profiled it:

    Code (csharp):
    1. // Keyboard polling: 9.504352E-06 s / frame
    2. // (as timed, avg of 1000 frames, profiler reports 0.00 ms)
    3.  
    4. private int[] values;
    5. private bool[] keys;
    6.  
    7. void Awake() {
    8.     values = (int[])System.Enum.GetValues(typeof(KeyCode));
    9.     keys = new bool[values.Length];
    10. }
    11.  
    12. void Update() {
    13.     for(int i = 0; i < values.Length; i++) {
    14.         keys[i] = Input.GetKey((KeyCode)values[i]);
    15.     }
    16. }
    Code (csharp):
    1. // OnGUI: 0.02 ms (as reported by profiler), 336 bytes GC / frame
    2. void OnGUI() {
    3.     // there is no code in here
    4. }
    Keyboard polling is more efficient.
     
  9. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Interesting - and certainly a concern if you're not targeting desktop platforms.
     
  10. daneshvar1998

    daneshvar1998

    Joined:
    May 10, 2018
    Posts:
    1
    if you want to know what character key is pressed
    you can go for a textinput
    an invisible textinput that detects wich key you pressed
    you simply add a on value changed mathod
    then you read whats in textfield and empty it again
    but you should make sure that you keep the input text selected and focused
     
  11. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Please don't necropost a 3-year-old thread just to post a solution that's significantly inferior to @guavaman 's solution that was posted up above.
     
  12. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Literally the worst possible solution to that problem.....
     
    Ruslank100, QFSW, el_nuru and 2 others like this.
  13. Bidule200

    Bidule200

    Joined:
    Apr 26, 2014
    Posts:
    18
    Far from ideal, but a very clever dirty hack indeed ^^
     
    FariAnderson likes this.
  14. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    See my comment above about not posting an inferior solution to an old thread. Your solution was already posted in this thread verbatim and then proven to be inferior.

    See @guavaman's comment above for information about why your solution is inferior.

    I mean, basically, just read the thread before you reply to it.
     
    Last edited: Oct 23, 2019
  15. kanareikatv

    kanareikatv

    Joined:
    Aug 8, 2019
    Posts:
    2
    Has just loggind to say that you are my hero, thanks, glad to you i have found name of button which i have searching for a day! Thanks
     
    FariAnderson likes this.
  16. AnneCHPostma

    AnneCHPostma

    Joined:
    Jul 12, 2012
    Posts:
    10
    I would add an Input.anyKeyDown check around the for loop, so the for loop would only be called when there actually is a key pressed down and not with every Update call, like so:

    Code (csharp):
    1. private int[] values;
    2. private bool[] keys;
    3.  
    4. void Awake() {
    5.     values = (int[])System.Enum.GetValues(typeof(KeyCode));
    6.     keys = new bool[values.Length];
    7. }
    8.  
    9. void Update() {
    10.     if (Input.anyKeyDown)
    11.     {
    12.         for(int i = 0; i < values.Length; i++) {
    13.             keys[i] = Input.GetKey((KeyCode)values[i]);
    14.         }
    15.     }
    16. }
     
    FariAnderson likes this.
  17. AnneCHPostma

    AnneCHPostma

    Joined:
    Jul 12, 2012
    Posts:
    10
    My current solution after reading all the comments would be:

    Code (csharp):
    1. private readonly Array keyCodes = Enum.GetValues(typeof(KeyCode));
    2.  
    3. void Update()
    4. {
    5.     if (Input.anyKeyDown)
    6.     {
    7.         foreach (KeyCode keyCode in keyCodes)
    8.         {
    9.             if (Input.GetKey(keyCode)) {
    10.                 Debug.Log("KeyCode down: " + keyCode);
    11.                 break;
    12.             }
    13.         }
    14.     }
    15. }
     
    Last edited: Feb 6, 2020
  18. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Dirty, yes. Ideal, no. Clever, also no. There's an input system for a reason...

    Have you benchmarked that this has any considerable gain on performance?
     
  19. el_nuru

    el_nuru

    Joined:
    Aug 27, 2016
    Posts:
    3
    to be fair that input system should allow a function like Input.getKeyUp, I have to say that danesh is at least showing more insight with that neat hack that the unity team forcing the user to go through a 3-year quest to get to a solution that doesn't use OnGUI, you know, like getKeyDown
     
    a436t4ataf likes this.
  20. el_nuru

    el_nuru

    Joined:
    Aug 27, 2016
    Posts:
    3
    I was wrong, it's still not working properly, maybe in 3 more years
     
  21. AnneCHPostma

    AnneCHPostma

    Joined:
    Jul 12, 2012
    Posts:
    10
    It's not considerable (didn't know that was a requirement???), but there is a gain yes.
    I don't need to do a benchmark to know it will be quicker (though not considerably), because the for loop will not be called on every update, and it will not continue to go through all possible key codes, once a key code has been matched.
    Common sense.
     
    a436t4ataf likes this.
  22. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Oh? You know how Input.anyKeyDown works internally, do you? Are you certain that Input.anyKeyDown doesn't do a loop through all the possible keys exactly like this does, essentially meaning that your suggestion would just do the exact same thing twice? Are you certain that Input.anyKeyDown is well-optimized? Did you write it yourself?

    I'm not saying that that's how Input.anyKeyDown works, but it's certainly possible that it is. It's possible that your method is faster; it's possible that it isn't. And you can't know which is the case without profiling.

    Quit trying to act like you know it all, because you don't. I'm not saying that to you specifically, but rather as a general point about programming.... and knowledge in general I suppose. You don't know it all, and you never will. Neither will I. Always consider the possibility that your "common sense" is wrong, especially when it comes to efficiency, because CPUs are not intuitive.
     
  23. AnneCHPostma

    AnneCHPostma

    Joined:
    Jul 12, 2012
    Posts:
    10
    Wow ... this is exactly why I usually stay clear from forums! What an emotional reaction on just some code! And the comment I made had nothing to do with the Input.anyKeyDown. Read my response properly, before starting to attack and offend people.

    I am going to play with the new Input system now and stop trying to help people ... *sigh*
     
  24. DeloitteCam

    DeloitteCam

    Joined:
    Jan 23, 2018
    Posts:
    22
    @AnnePostma, ignore StarManta, I thought your suggestion was on the money and profiled it myself, it did make things faster.

    It's a pity someone with 7000+ posts didn't actually contribute any new ideas or constructive input to this thread yet managed to scare off a literal 1st poster (daneshvar1998) who seems to have never come back and yourself who had all of 6 posts at the time.

    If we had more posts by people like you and less from people like StarManta I think this forum would be a much better community. I'd certainly visit and contribute more often.

    Here's my revision, it also removes mouse and joystick keycodes and casts to a typed array so the look doesn't have to have a cast in it:

    Code (CSharp):
    1.  
    2. private static readonly KeyCode[] keyCodes = Enum.GetValues(typeof(KeyCode))
    3.                                                  .Cast<KeyCode>()
    4.                                                  .Where(k => ((int)k < (int)KeyCode.Mouse0))
    5.                                                  .ToArray();
    6.  
    7. private static KeyCode? GetCurrentKeyDown()
    8. {
    9.     if (!Input.anyKey)
    10.     {
    11.         return null;
    12.     }
    13.  
    14.     for (int i = 0; i < keyCodes.Length; i++)
    15.     {
    16.         if (Input.GetKey(keyCodes[i]))
    17.         {
    18.             return keyCodes[i];
    19.         }
    20.     }
    21.     return null;
    22. }
    23.  
    This also trims about 170 keycodes from the list for mouse and joystick codes which might return false positives and casts the list to the correct type to avoid having the foreach do the cast. The
    < (int)KeyCode.Mouse0
    but trims the mouse and joystick codes as they're all at the end of the enumeration (323 to 509). A little hacky but I think that usage is ok because keyboards aren't likely to grow new keys and unity would not risk breaking changes in re-numbering such an often used enumeration.

    Note this will run every frame when held down, change line 9 anyKey to anyKeyDown for it to only return once then null every other frame till the next time a key is pressed.

    Profiling results (4.7 GHz i7 8700K):
    My solution - Key held down - 0.2 microseconds to 4.8 microseconds (1000 microseconds = 1 millisecond).
    My solution - No keys down - 0.06 microseconds.
    Previous Solution - 6.9 microseconds every frame, key down or not.

    Splitting hairs on a my desktop rig but you want every last cycle on some form factors - I've seen similar micro optimizations effecting constant time performance add measurable minutes in battery life.

    I also think necroing threads, no matter how old, is actually really important because threads like this tend to have high google rankings so keeping them current and fresh is vital to keeping the number of repeat questions to a minimum.
     
    Last edited: Jun 4, 2020
  25. ProgrammerTurtle

    ProgrammerTurtle

    Joined:
    Oct 8, 2018
    Posts:
    28
    No. A big no. This is like shooting your self on the foot on purpose.
     
  26. mechane

    mechane

    Joined:
    Nov 17, 2018
    Posts:
    6
    I agree. I sometimes found interesting answers on very old posts that get refreshed years after years.

    I was not ready for this amount of arrogance today, i have to say this thread brought me some fun.
     
  27. Sushi271

    Sushi271

    Joined:
    Mar 22, 2014
    Posts:
    2
    Couldn't agree more. We need more kindess in the world nowadays. Especially nowadays. StarManta should certainly work on their attitude...

    Thank you for your contribution. I actually decided to improve on your solution as well, although it's more cosmetic I think. Basically I decided to create a class out of it that contains your solution, albeit modified. I noticed you only return the first key. However slight the possibility of hitting two keys on the same frame is, it is not zero. For GetKey() it shouldn't matter that much, although for GetKeyDown() it will make program omit the key entirely. My solution is to yield return the key instead, making it an IEnumerable. If someone wants the first one anyway, they can always call FirstOrDefault() on the result.

    To my surprise, UnityEngine.Input seems to lack anyKeyUp flag. So for checking list of just released keys - no speed up, sorry. Unless I'm missing something heavily :) Hope this will help someone.

    Code (CSharp):
    1. public static class UltiInput
    2. {
    3.     static readonly KeyCode[] _keyCodes =
    4.         System.Enum.GetValues(typeof(KeyCode))
    5.             .Cast<KeyCode>()
    6.             .Where(k => ((int)k < (int)KeyCode.Mouse0))
    7.             .ToArray();
    8.  
    9.     public static IEnumerable<KeyCode> GetCurrentKeysDown()
    10.     {
    11.         if (Input.anyKeyDown)
    12.             for (int i = 0; i < _keyCodes.Length; i++)
    13.                 if (Input.GetKeyDown(_keyCodes[i]))
    14.                     yield return _keyCodes[i];
    15.     }
    16.  
    17.     public static IEnumerable<KeyCode> GetCurrentKeys()
    18.     {
    19.         if (Input.anyKey)
    20.             for (int i = 0; i < _keyCodes.Length; i++)
    21.                 if (Input.GetKey(_keyCodes[i]))
    22.                     yield return _keyCodes[i];
    23.     }
    24.  
    25.     public static IEnumerable<KeyCode> GetCurrentKeysUp()
    26.     {
    27.         for (int i = 0; i < _keyCodes.Length; i++)
    28.             if (Input.GetKeyUp(_keyCodes[i]))
    29.                 yield return _keyCodes[i];
    30.     }
    31. }
    EDIT: What's more interesting, KeyCode with int representation 0, is actually... KeyCode.None! which makes it being returned by FirstOrDefault() if the enumeration is empty. Also this looks like a better candidate for your function result, if there's no key pressed, instead of null. Therefore nullable return type is not really necessary.
     
    Last edited: Jul 2, 2020
    wpetillo, altair2020 and Canoa22 like this.
  28. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    With thanks to: @DeloitteCam @AnnePostma and of course @guavaman ... here's what I believe should have been built-in to Unity 10 years ago: KeyUp, KeyDown, and KeyPress, all working nicely:

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Linq;
    6. using UnityEngine.Events;
    7.  
    8. /**
    9. * Because Unity refused to fix their bugs in Input.*, didn't fix the missing methods in UI.* text-input classes,
    10. * and instead started work on a new InputSystem that still isn't complete and live :).
    11. *
    12. * c.f. https://forum.unity.com/threads/find-out-which-key-was-pressed.385250/
    13. */
    14. public class UnityBugInputFieldKeypressListener : MonoBehaviour
    15. {
    16.     [Serializable]
    17.     public class KeyCodeEvent : UnityEvent<KeyCode>
    18.     {
    19.     }
    20.  
    21.     public KeyCodeEvent keyDownListener,keyUpListener,keyPressListener;
    22.  
    23.     private static readonly KeyCode[] keyCodes = Enum.GetValues(typeof(KeyCode))
    24.         .Cast<KeyCode>()
    25.         .Where(k => ((int)k < (int)KeyCode.Mouse0))
    26.         .ToArray();
    27.  
    28.     private List<KeyCode> _keysDown;
    29.  
    30.     public void OnEnable()
    31.     {
    32.         _keysDown = new List<KeyCode>();
    33.     }
    34.     public void OnDisable()
    35.     {
    36.         _keysDown = null;
    37.     }
    38.  
    39.     public void Update()
    40.     {
    41.         if( Input.anyKeyDown )
    42.         {
    43.             for (int i = 0; i < keyCodes.Length; i++)
    44.             {
    45.                 KeyCode kc = keyCodes[i];
    46.                 if (Input.GetKeyDown(kc))
    47.                 {
    48.                     _keysDown.Add(kc);
    49.                     keyDownListener?.Invoke( kc );
    50.                 }
    51.             }          
    52.         }
    53.  
    54.         if( _keysDown.Count > 0 )
    55.         {
    56.             for( int i=0; i<_keysDown.Count; i++ )
    57.             {
    58.                 KeyCode kc = _keysDown[i];
    59.                 if( Input.GetKeyUp(kc) )
    60.                 {
    61.                     _keysDown.RemoveAt(i);
    62.                     i--;
    63.                     keyUpListener?.Invoke(kc);
    64.                     keyPressListener?.Invoke(kc);
    65.                 }
    66.             }
    67.         }
    68.     }
    69. }
    With this, you can simply subscribe (both in Editor GUI/Inspector, and in code), to whichever callback you wanted:

    KeyDownListener
    KeyUpListener
    KeyPressListener

    ...and you'll get the callbacks correctly.
     
    gilcraos, IDGG, Lekteroi and 6 others like this.
  29. MrEpicness

    MrEpicness

    Joined:
    Jun 3, 2020
    Posts:
    1
    You should note that you need to make sure you include "using System.Linq;" at the top of your code (or where ever you put your "using" statements) in order for the ".Cast<KeyCode>()" on line 3 to be recognized. Otherwise you will get an error saying that "Array does not contain a definition for "Cast"...".
     
  30. ngwood111

    ngwood111

    Joined:
    Sep 10, 2020
    Posts:
    8
    Well, I mean, you might be right, apart from in the documentation where it explicitly states that anyKeyDown is a property with type bool and not a method.

    But do tell how you think

    .loop
    cmp;
    cmp;
    cmp;
    jmp .loop;

    is going to be more efficient than

    cmp;
    jge .loop;
     
  31. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,991
    Why do you bump this thread? You know that a property is a method / set of methods, right? So I don't get your point.

    While I'm pretty sure that anyKeyDown most likely will just check a flag on the native side, we don't know the implemenation of the get method. It's often not clear what a property does behind the scenes. Like the touches property which explicitly allocates a new array each time it's read. So here it's better to use touchCount and GetTouch in a loop.

    So even StarManta might have overreacted a little bit, I'm more on his side. If you don't know the exact implementation of a method you have to profile / benchmark your code in order to know what is faster. Keep in mind that StarManta mainly objected the statement:

     
  32. ngwood111

    ngwood111

    Joined:
    Sep 10, 2020
    Posts:
    8
    I responded because I wanted to? Actually, I wanted to figure out how Unity is handling keybindings which brought me here. Anne shared sound advice and instead of thanking her for that dude decided he was going to try to trip them up and then berated them for being a "know it all" because they're smart enough to know they don't need to benchmark every thing in the world.

    And I'm aware, but you shouldn't use properties like that, and it's irrelevant either way because literally two lines later the docs say "You should be polling this variable from the Update function, since the state gets reset each frame." which tells us pretty clearly how it's being used and how we should use it.

    You don't need to profile everything to know what's good code and what's bad, you CAN use logic and common sense, and you SHOULD use logic and common sense first before wasting your time benchmarking.

    Let's say there are 325 possible keys, and now we KNOW from the docs that there isn't any crazy stuff going with the anyKeyDown function, it's simply cmp and jmp if true. Let's say that's 2 instructions and we'll be generous and say that every instruction takes the same amount of time.

    If I run a loop that tests every single key, I have to perform at minimum those same 2 instructions x 325 = 650 instructions every single frame. If I have 30 fps that means every second I have to perform 19,500 instructions.

    If instead I'm using the code that the dude freaked out about, the worst case scenario is that I will need to do (2x325+2)*30 instructions per second, or 19,560 instructions. This worst case scenario would be when the user is holding down a key, I lose 60 instructions.

    If there is even ONE frame in a second where the user was not pressing a key however, rather than using 19,500 instructions we will only use 18,910 instructions. I.E. if you take your finger off the keyboard for even a fraction of a second to pick your nose, we have already reduced the number of instructions hundreds of times more than it would have been and that's even before we start accounting for other inefficiencies in the code.
     
  33. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    So...this example doesn't make a ton of sense. If anyKeyDown enumerates every key code to check (which, I agree with you, it probably doesn't) then a frame with no input is going to use the same number of instructions whether or not you check first or enumerate directly yourself. You're basically saying "If I check the property that enumerates before enumerating and it returns false then I only have to do 1 enumeration." which - yeah, you'd only do 1 enumeration if you did it yourself directly in the first place.

    StarManta probably could have worded his response better but I do agree with the general sentiment. If you say "Do this because it's faster" and I ask "how much faster" and you can't tell me or even worse say "I don't have to see how much faster because I just know" then I'm going to push back on your assertion.

    With all that said, this example is a bit contrived and there are better contributions in the thread about polling input.
     
    Gallareton and Bunny83 like this.
  34. Meijer

    Meijer

    Joined:
    Jun 11, 2015
    Posts:
    15
    I know it's an old thread, but if anyone is still looking for a solution:
    Code (CSharp):
    1.  
    2. private void Update()
    3. {
    4.     checkInput();
    5. }
    6.  
    7. private void checkInput(){
    8.         if (!Input.anyKeyDown)
    9.             return;
    10.  
    11.         foreach (KeyCode key in listOfMinigameInput)
    12.             if (Input.GetKeyDown(key))
    13.                 switch (key)
    14.                 {
    15.                     case KeyCode.W:
    16.                         Debug.Log($"Pressed {key}");
    17.                         break;
    18.                     case KeyCode.A:
    19.                         Debug.Log($"Pressed {key}");
    20.                         break;
    21.                     case KeyCode.S:
    22.                         Debug.Log($"Pressed {key}");
    23.                         break;
    24.                     case KeyCode.D:
    25.                         Debug.Log($"Pressed {key}");
    26.                         break;
    27.                     default:
    28.                         Debug.Log("No key was pressed");
    29.                         break;
    30.                 }
    31. }
    32.                 }
    listOfMinigameInput being an array of KeyCode, in my case like so:
    Code (CSharp):
    1. private KeyCode[] listOfMinigameInput = new KeyCode[4]
    2.     {
    3.         KeyCode.W,
    4.         KeyCode.A,
    5.         KeyCode.S,
    6.         KeyCode.D
    7.     };
    extend on this as you need
     
    FariAnderson likes this.
  35. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    I'm sure you intended well, but ... as far as I can see you've taken the already-posted solution, removed all the good bits, and you're presenting something that cannot solve the original problem in any way?

    Please don't post stuff that adds nothing and drives the solution backwards.
     
  36. introvertss

    introvertss

    Joined:
    Dec 29, 2020
    Posts:
    3

    Yes it works but i have a question why are their 2 messages printed to the console, the first being "the key code" and the second being the message "none". Although this second message appears only for a few keys.
     
  37. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
  38. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,991
    The None keycode is used when you get an additional "character event". There is no seperate event type for characters. If you get a KeyDown event and the keycode is None, it's probably a character event and you should check the character property if you're interested in the character. If not, just ignore None keycodes.
     
    arfish and _geo__ like this.
  39. introvertss

    introvertss

    Joined:
    Dec 29, 2020
    Posts:
    3
    This is what happens when the space key is pressed twice. So i just don't get wat the problem is and also
    my keyboard is a standard Ansi Keyboard with a window's OS.
    upload_2021-5-17_13-3-34.png
     
  40. introvertss

    introvertss

    Joined:
    Dec 29, 2020
    Posts:
    3
    Ok...Thank you will do
     
  41. AntonShakalo

    AntonShakalo

    Joined:
    Jun 22, 2021
    Posts:
    3
    So I went ahead and slightly adjusted code from
    Sushi271 answer:


    Code (CSharp):
    1.  using System.Collections.Generic;
    2.     using System.Linq;
    3.     using UnityEngine;
    4.  
    5.     /// <summary>
    6.     /// Util to help determine current keyboard keys pressed.
    7.     /// Does not support mouse and joystick key codes
    8.     /// </summary>
    9.     public static class KeyboardInputHelper
    10.     {
    11.         static readonly KeyCode[] _keyCodes =
    12.             System.Enum.GetValues(typeof(KeyCode))
    13.                 .Cast<KeyCode>()
    14.                 .Where(k => k < KeyCode.Mouse0)
    15.                 .ToArray();
    16.  
    17.         /// <summary>
    18.         /// Get information about interesting keys pressed
    19.         /// </summary>
    20.         /// <param name="interestingCodes"></param>
    21.         /// <returns>True if any of provided keys is down</returns>
    22.         public static bool IsAnyKeyDown(params KeyCode[] interestingCodes)
    23.         {
    24.             return Enumerable.Intersect(GetCurrentKeys(), interestingCodes).Any();
    25.         }
    26.  
    27.         /// <summary>
    28.         /// Get information about interesting keys pressed
    29.         /// </summary>
    30.         /// <param name="interestingCodes">Interesting key codes</param>
    31.         /// <returns>True if all of provided keys is down</returns>
    32.         public static bool IsAllKeyDown(params KeyCode[] interestingCodes)
    33.         {
    34.             return Enumerable.SequenceEqual(GetCurrentKeys(), interestingCodes);
    35.         }
    36.  
    37.         /// <summary>
    38.         /// Get current keys pressed on keyboard including special keys like <see cref="KeyCode.LeftControl"/>
    39.         /// </summary>
    40.         /// <returns>Iterator with pressed keys. If nothing is pressed, empty iterator is returned</returns>
    41.         /// <remarks>Be careful with FirstOrDefault. It will return KeyCode.None if nothing is pressed because of its implementation</remarks>
    42.         public static IEnumerable<KeyCode> GetCurrentKeys()
    43.         {
    44.             if (Input.anyKeyDown)
    45.             {
    46.                 for (int i = 0; i < _keyCodes.Length; i++)
    47.                     if (Input.GetKey(_keyCodes[i]))
    48.                         yield return _keyCodes[i];
    49.             }
    50.         }
    51.  
    52.         /// <summary>
    53.         /// Get current keys unpressed on keyboard including special keys like <see cref="KeyCode.LeftControl"/>
    54.         /// </summary>
    55.         /// <returns>Iterator with unpressed keys. If nothing is pressed, empty iterator is returned</returns>
    56.         /// <remarks>Be careful with FirstOrDefault. It will return KeyCode.None if nothing is pressed because of its implementation</remarks>
    57.         public static IEnumerable<KeyCode> GetCurrentKeysUp()
    58.         {
    59.             for (int i = 0; i < _keyCodes.Length; i++)
    60.                 if (Input.GetKeyUp(_keyCodes[i]))
    61.                     yield return _keyCodes[i];
    62.         }
    63.     }
    Now you can ask if any or all of interesting kodes are presented in input
     
    EAWilliams likes this.
  42. Rachan

    Rachan

    Joined:
    Dec 3, 2012
    Posts:
    776

    Thank you very much! it works!!!
     
  43. Edy

    Edy

    Joined:
    Jun 3, 2010
    Posts:
    2,508
    Just a minor optimization, also applicable to the other implementations. As the side of the array doesn't change within the loop you don't need to query its length in each single iteration. Just get the size once and iterate:

    Code (csharp):
    1. private int[] values;
    2. private bool[] keys;
    3.  
    4. void Awake()
    5.     {
    6.     values = (int[])System.Enum.GetValues(typeof(KeyCode));
    7.     keys = new bool[values.Length];
    8.     }
    9.  
    10. void Update()
    11.     {
    12.     for (int i = 0, n = values.Length; i < n; i++)
    13.         keys[i] = Input.GetKey((KeyCode)values[i]);
    14.     }
    15.  
     
    FariAnderson likes this.
  44. wpetillo

    wpetillo

    Joined:
    May 23, 2017
    Posts:
    24
    For those who crave the convenience of UnityEvents, here is an another script that builds off of Sushi271's answer:

    Code (CSharp):
    1.     public class GetKey : MonoBehaviour
    2.     {
    3.         [SerializeField] KeyCodeEvent keyDown;
    4.         [SerializeField] KeyCodeEvent keyHold;
    5.         [SerializeField] KeyCodeEvent keyUp;
    6.  
    7.         bool useKeyDown;
    8.         bool useKeyHold;
    9.         bool useKeyUp;
    10.        
    11.         void OnValidate()
    12.         {
    13.             useKeyDown = keyDown.GetPersistentEventCount() > 0;
    14.             useKeyHold = keyHold.GetPersistentEventCount() > 0;
    15.             useKeyUp = keyUp.GetPersistentEventCount() > 0;
    16.         }
    17.        
    18.         IEnumerable<KeyCode> keys;
    19.  
    20.         void Update()
    21.         {
    22.             if (useKeyDown) Output(UltiInput.GetCurrentKeysDown(), keyDown);
    23.             if (useKeyHold) Output(UltiInput.GetCurrentKeys(), keyHold);
    24.             if (useKeyUp) Output(UltiInput.GetCurrentKeysUp(), keyUp);
    25.         }
    26.        
    27.         void Output(IEnumerable<KeyCode> keys, KeyCodeEvent output)
    28.         {
    29.             if (keys == null) return;
    30.             foreach (var key in keys)
    31.                 output.Invoke(key);
    32.         }
    33.     }
     
  45. sentar

    sentar

    Joined:
    Feb 27, 2017
    Posts:
    44

    I love you, it worked with my implementation which I will say may not be professional or optimal but it works and I enjoyed your code. I searched this on google and I have to say after looking at 2010's forums I'm glad people wrote in this one to help learners like me.

    I added this to your code

    Code (CSharp):
    1.  
    2.  
    3. [Serializable]
    4.     public class KeyCodeListEvent : UnityEvent<List<KeyCode>>
    5.     {
    6.     }
    7.  
    8. public KeyCodeListEvent keyDownList;
    9.  
    10.  
    and in your If statement for the _keysDown if the count is greater than 0, after the forloop

    I did your invoke:

    Code (CSharp):
    1.  
    2. keyDownList.Invoke(_keysDown);
    3.  
    then passed your list to my settings manager script

    Code (CSharp):
    1.  
    2.  
    3. public void WasKeyPressed(List<KeyCode> key)
    4.     {
    5.         eventkey = key;
    6.     }
    7.  
    8.     public List<KeyCode> eventkey;
    9.  
    10.  
    then with my controller script

    Code (CSharp):
    1.  
    2.  
    3. //a simple get keycode loop through the settings manager function to a serializable class with keycode and enum value pertaining to the GameObject Input Manager I'm implementing
    4. if (SM.eventkey.Contains(SM.MyGetKey(MyKeyBindings.Forward)))
    5.         {
    6.         }
    7.  
    Like I said I'm learning this all by myself over the years and thank you again for bringing up this solution!
     
    Last edited: Apr 7, 2022
  46. peterfiftyfour

    peterfiftyfour

    Joined:
    Jan 8, 2016
    Posts:
    20
    Hey all! If you are using the new input system this seems to work great and is more intuitive to me:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.InputSystem;
    3.  
    4. public class Blah : MonoBehaviour
    5. {
    6.     protected void OnEnable()
    7.     {
    8.         Keyboard.current.onTextInput += OnTextInput;
    9.     }
    10.  
    11.     protected void OnDisable()
    12.     {
    13.         Keyboard.current.onTextInput -= OnTextInput;
    14.     }
    15.  
    16.     private void OnTextInput(char ch)
    17.     {
    18.         print(ch);
    19.     }
    20. }
    This has some limitations but I think if you want more control you can use onEvent. There's some more stuff here:
    https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Events.html
     
  47. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    That doesn't actually work. What 'char' is "left shift key"? :). You've missed half what's being provided here.

    Anyway ... Doing it with the new input system is a very different problem (with a lot more power/options than if you're using old input) - I wouldn't do it the way you describe (there are a lot of other things to worry about when using new input).
     
    peterfiftyfour likes this.
  48. peterfiftyfour

    peterfiftyfour

    Joined:
    Jan 8, 2016
    Posts:
    20
    Haha true .. hmm after playing around a bit this is what I came up with

    Code (CSharp):
    1. using UnityEngine;
    2. using TMPro;
    3. using UnityEngine.InputSystem;
    4. using System;
    5. using UnityEngine.InputSystem.Utilities;
    6. using UnityEngine.InputSystem.LowLevel;
    7.  
    8. public class InputManager : MonoBehaviour
    9. {
    10.     private IDisposable _eventListener;
    11.  
    12.     private void OnEnable()
    13.     {
    14.         _eventListener = InputSystem.onEvent.ForDevice(Keyboard.current).Call(OnKeyPressed);
    15.     }
    16.  
    17.     private void OnDisable()
    18.     {
    19.         _eventListener.Dispose();
    20.     }
    21.  
    22.     private void OnKeyPressed(InputEventPtr eventPtr)
    23.     {
    24.         if (!eventPtr.IsA<StateEvent>() && !eventPtr.IsA<DeltaStateEvent>())
    25.         {
    26.             return;
    27.         }
    28.  
    29.         foreach (var control in eventPtr.EnumerateChangedControls())
    30.         {
    31.             print(control.name);
    32.         }
    33.     }
    34. }
    You would have to do your own keyup key down stuff (perhaps theres something for this already but the docs are sparse) but this might be more what was asked for? What other problems with the new input system were you thinking about?
     
    Last edited: May 7, 2022
    s_xgx1 and langtusaupt like this.
  49. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    If you're going to do it using new input then there are much better dedicated API calls specifically for doing this - your code above is needlessly convoluted, I recommend reading the new input docs which have a lot of detail on how to capture input. I don't think it's difficult to do, and I don't think it needs a thread of its own. This thread was created because the old input system was missing a few API calls.
     
    peterfiftyfour likes this.