5
\$\begingroup\$

I've been building an IDE using C# and only the console. To get keyboard input in real time (as opposed to a read–eval–print loop,) I have the following method to get keyboard input:

public static ConsoleKeyInfo[] GetInput()
{
    // A list of characters
    List<ConsoleKeyInfo> input = new List<ConsoleKeyInfo>();

    // Loop while keys are available or we hit 10 keys
    for (int i = 0; Console.KeyAvailable && i < 10; i++)
    {
        // Read a key (preventing it from being printed) 
        // and put it in the key list (if it's not in there yet)
        ConsoleKeyInfo info = Console.ReadKey(true);
        if (!input.Contains(info))
        {
            input.Add(info);
        }
    }

    // Use up any remaining key presses
    while (Console.KeyAvailable)
    {
        // Read a single key
        Console.ReadKey(true);
    }

    // Convert the list to an array and return
    return input.ToArray();
}

GetInput called once at the start of the main loop and the result is passed into objects that handle key presses:

ConsoleKeyInfo[] keysHit = ConEx.ConEx_Input.GetInput();
Program.Interpreter.Update(Program.Interpreter.CurMode, keysHit);
Program.WindowUI.Update(Program.Interpreter.CurMode, keysHit);
Program.WindowSideBar.Update(Program.Interpreter.CurMode, keysHit);

Inside an Update method:

for (int i = 0; i < keysHit.Length; i++)
{
    switch (keysHit[i].Key)
    {
        //Cycle through the pages
        case ConsoleKey.Home:
            //Do some stuff
            break;
        case ConsoleKey.End:
            //Do other stuff
            break;
    }
}

Is this a sub optimal solution for getting keyboard input? I'm very willing to breakout P/Invoke or a threaded solution if need be. I can't support an event handler based solution due to the tight control of sequence needed.

Edit: Nikita B's answer is marked as Accepted because it reduced the amount of ticks taken from ~60 to ~30. Thanks!

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

You could join the two loops. I think this way your intent will be clearer, and it's not like a few extra comparisons are going to cost you anything.

//return "IEnumerable<T>" if all you need to do is iterate over elements
public static IEnumerable<ConsoleKeyInfo> GetInput()
{
    //use "var" if return type is obvious from context
    //use "HashSet<T>" if you need a collection of unique items
    var input = new HashSet<ConsoleKeyInfo>();
    var keyCount = 0;
    while (Console.KeyAvailable)
    {
        var key = Console.ReadKey(true);
        //use constants instead of magic numbers
        if (++keyCount > MaxInputLength) continue;
        //no need to call "Contains", non-unique items will be dropped automatically
        input.Add(key);
    }
    //no need to convert anything
    return input;
}

But I have to question your design. Why do I have to input (and memorize?) a 10-key sequence where every key means something and the order is important? Sounds like a really poor user experience. I feel like it is not the way to go in modern applications, iddqd or not.

Edit: I forgot, that HashSet does not preserve insertion order. So if order is important, you should stick to List (your original approach).

\$\endgroup\$
2
  • \$\begingroup\$ There is no memorization and the order is not important (thanks for the HashSet idea.)The i < n keys is to limit the amount of keys that can be mashed on at once. In \$\endgroup\$
    – tngreene
    May 10, 2016 at 22:28
  • \$\begingroup\$ To continue past 5 minute timeout: "No event handlers" refers to the whole program design. The editor behaves like Notepad, except one can type and paste in any cardinal direction (among other cool features.) Link if you want to try it. GetInput() is from a professor for a console arcade game. I never had a reason to inspect it closely until now. I always assumed there was a reason for the < 10 (Professors are always right, right? -Naive freshman in 2011.) \$\endgroup\$
    – tngreene
    May 10, 2016 at 22:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.