Get corresponding Key From Input

I have an interact-able terminal with a keyboard, and I want the keys to move down depending on which key has been pressed (A moves A, B moves B etc…) but aside from having a MASSIVE variables setup for each key, and an equally-sized set of if statements or a switch case, I am unsure of how to do this.

I wanted to find a simple, small way of doing this for optimisation purposes.

Does anyone have any suggestions for how this could be done without a huge script?

/*
* Keys to move: 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, /, *, -
*              Q, W, E, R, T, Y, U, I, O, P, BACKSPACE, +
*              A, S, D, F, G, H, J, K, L, RETURN, =
*              Z, X, C, V, B, N, M, UP ARROW
*              SPACE, LEFT ARROW, DOWN ARROW, RIGHT ARROW, .
* */

using UnityEngine;

[System.Serializable]
public class Keys
{
    public string letter;
    public GameObject key;
}

public class KeyPressDown : MonoBehaviour
{
    //Default Key Height -0.0475, Drop to -0.08
    [SerializeField]
    public Keys[] keys;

    void Update()
    {
        //Get key pressed, then move it
    }
}

On-Screen keyboard? Maybe something as simple as 1 key/script per key with its relative "If (Input.GetKey ". :slight_smile:

No, not on-screen, physical (not the right word when it is all digital ;D), model(s).

I want to move those keys down when you press the same (corresponding) key on your own keyboard.

The issue is that I don’t want 49-odd if statements or cases just to get this working, I was hoping there would be a better (smaller) way of doing it.

Well, okay physical… right… but something “visual” :slight_smile:
One script per object doesn’t sound so bad, that just looks for the key.
Make 1 script with a variable. and change the variable (set it) 49-odd different times. And you’re done? :slight_smile:
I’m thinking and thinking… not sure how it can be simpler.

I think checking the keys has to be a loop. Unity doesn’t have anything where you can just ask for whatever was pressed this frame, like KeyCode[ ] GetKeysDown(). Can check for anyKeydown beforehand.

But you’re talking about just setting it up. I’d change “string letter” in the key class to KeyCode. The key codes map to the ASCII for most letters – (int)KeyCode.A is 97. Even ‘\t’ is the same as KeyCode.Tab (9) and ‘\r’ is KeyCode.Return (13.) So you could fill most of your Keys array from things like string row2="\tqwerty..." and a loop. Use an X or something for special cases and hand-fill those later (like CapsLock and shift left/right.)

Okay, I have set up the script to work individually on keys, but some keys, such as period, asterisk, slash, minus and equals have keypad alternatives (KeypadPeriod, KeypadMultiply, KeypadDivide, KeypadMinus and KeypadEquals).

I modified the script to work with an array of KeyCodes, so I could add multiple correspondents per key, but it only seems to work with one of them (only 1 of the keys listed in the array cause the key to drop).

I believe this may have something to do with the way I loop through the array (using a foreach).

/*
* Keys to move: 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, /, *, -
*              Q, W, E, R, T, Y, U, I, O, P, BACKSPACE, +
*              A, S, D, F, G, H, J, K, L, RETURN, =
*              Z, X, C, V, B, N, M, UP ARROW
*              SPACE, LEFT ARROW, DOWN ARROW, RIGHT ARROW, .
* */

using UnityEngine;

public class KeyPressDown : MonoBehaviour
{
    //Default Key Height -0.0475, Drop to -0.08
    public KeyCode[] letter;
    public enum Position { Up, Down }
    public Position status;

    void Update()
    {
        Debug.Log(Input.inputString);
        //Get key pressed, then move it
        foreach(KeyCode l in letter)
        {
            if (Input.GetKey(l))
            {
                transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, -0.08f);
            }
            else
            {
                transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, -0.0475f);
            }
        }
    }
}

You’re moving the object this script is attached to but unless you press the last key in the array you’ll just see the object at -0.0475 on the Z axis.

Is each “letter” a GameObject? If so then you just need a script to map a keycode to that GameObject and move it depending on whether or not the key is held down. You don’t need an array at all.

KeyCode keyCode;

void Update()
{
    if (Input.GetKey(keyCode))
        // move down
    else
        // move up
}

Then you’d just attach that script to the GameObjects that need to respond to input and set the key code they should check in the Inspector

This script is on each key? Or there is just one script?

Edit: Just after the latest reply, I posted. The above solution is what I was thinking about in my original message. :slight_smile: That seems easiest. Then, adjust the position of the GameObject on which the script resides? :slight_smile:

There is an instance of this script on each Key GameObject, The “letter” KeyCode array is the real-world key that corresponds to that in-game key, it dictates which keys it will move with.

Doesn’t change the fact that you’re executing the loop on every object.

With your current code - If I press A it will move the object to -0.08 on the Z axis but the next check (for B) is false so it just moves it back again. All this happens in the same frame so you never perceive anything happening.

Kelso: I think originally, key[ ] Keys; was an array of every possible key, on a single script. When it got changed to one script per “key” gameObject, it was accidentally kept as an array, also with the not-now-needed loop.

I think the point of having 1 script/gameObject was being able to go through the Inspector and hand-enter “LeftArrow” and so on into every field. I’m not sure if the OP is doing that, or using my suggesting to init them in code (based on having a single gameObject.) I don’t see the point of having one gameObject on each. But it’s a Unity idiom, and those can really make people feel more comfortable.

I think the basic problem the OP has now is conflicting advice overload.

This was originally true, but they do have a function (although it doesn’t work).

The array is meant to list all keys that will move this object, for example there are 2 period keys on a full-length keyboard, one in the main key section below L, and another on the keypad (numpad), this array was designed so that both keys would move that key in-game, except it only works for the last in the array :frowning:


I now have a script which only activates the KeyPressDown objects when I am using a terminal, to prevent rogue presses being detected when I am walking about in-game.

Apart from hitting a frankly disgraceful 9fps when used, the script below works as I want it to, when the key is pressed on your keyboard, that key (object) moves down in-game (apart from the issue mentioned above).

The issue is that when I put it in a function (method) of it’s own, the key only goes down, it’s like the ultimate version of sticky-keys, and the key only goes back up when a different key is pressed.

I need a way to maintain it’s current functionality, but get a bit (LOT) more performance out of it.

/*
* Keys to move: 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, /, *, -
*              Q, W, E, R, T, Y, U, I, O, P, BACKSPACE, +
*              A, S, D, F, G, H, J, K, L, RETURN, =
*              Z, X, C, V, B, N, M, UP ARROW
*              SPACE, LEFT ARROW, DOWN ARROW, RIGHT ARROW, .
* */

using UnityEngine;

public class KeyPressDown : MonoBehaviour
{
    //Default Key Height -0.0475, Drop to -0.08
    public KeyCode[] letter;
    public enum Position { Up, Down }
    public Position status;
    void Update()
    {
        //if (Input.anyKey)
        {
            //OnKeyPress();
            Debug.Log(Input.inputString);
            //Get key pressed, then move it
            foreach (KeyCode l in letter)
            {
                if (Input.GetKey(l))
                {
                    //Key Down
                    transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, -0.08f);
                }
                else
                {
                    //Key Up
                    transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, -0.0475f);
                }
            }
        }
    }
}

Ya… I don’t want to add to that. One script referencing a list or 1 script on each… In the beginning, he was asking about a simple way to do this (much more generally speaking). I believe from here he has good options.

Ah, I think I know the reason for your small array problem. And I remember that now, how it’s for the 2 keys (where applicable). modify your code:

bool gotkey = false;
foreach (KeyCode l in letter)
            {
                if (Input.GetKey(l)) gotkey = true;
}
if(gotkey){            
                    //Key Down
                    transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, -0.08f);
                }
                else
                {
// if you stored the state, you would only have to move it up if it changed.*
                    //Key Up
                    transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, -0.0475f);
                }
            }

Otherwise you’re saying if ‘.’ is down, press down… otherwise up, and if keypad ‘.’ is down do the same. You’d have to have both down in that situation to see it, otherwise one would override the other, based on its position in the array :slight_smile:
‘.’ = “period” key. lol

Gotcha. Get rid of your else and just set the position to the “unmoved” location at the top of the loop and only move it if you hit a key in the loop. For added benefit - stop looping when you hit a true condition.

// reset position at the top of the loop
transform.position = originalPosition;
// enumerate keys and move if necessary
foreach (var key in keys)
{
    if (Input.GetKeyDown(key))
    {
        transform.position = ......;
        break;
    }
}