0

I am learning about socket messaging. I interrupted Console.ReadKey() in a while loop and a lot of the calls ended up incomplete. I am trying to find a way to remove the incomplete calls without the user typing it all out.

I have seen

while(Console.KeyAvailable){Console.ReadKey(true);}

but I have the opposite problem too many calls not enough Key strokes.

How to add a Timeout to Console.ReadLine()? This question got me to where I am now, but it doesn't solve my current problem.

using System;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        DontLockOnCharGet bug = new DontLockOnCharGet();
        bug.Setup();
    }
}

public class DontLockOnCharGet
{
    public void Setup()
    {
        while (true) { DontLockCharGet(); }
    }

    public void DontLockCharGet()
    {
        while (true)
        {
            // used to interrupt the Console.ReadKey() function
            AutoResetEvent getInput = new AutoResetEvent(false);
            AutoResetEvent gotInput = new AutoResetEvent(false);

            // Console.ReadKey() assigns to input
            char input = ' ';

            //Lambda used to get rid of extra class
            Thread tom = new Thread(() =>
            {
                getInput.WaitOne(); // Waits for getInput.Set()

                //The problem with this is the read keys stacking up
                // causing the need for a lot of keystrokes
                input = Console.ReadKey().KeyChar;

                gotInput.Set();
            })
            {
                IsBackground = true
            };
            // Starts Lambda function
            tom.Start(); 

            // Allows thread to pass WaitOne() in Lambda
            getInput.Set(); 
            // Gives some milliseconds for before stopping Lambda exe
            gotInput.WaitOne(2000);

            if (input == 'S' || input == 's')
            {
                break;
            }
            // thinking I would put the solution here
            //...
        }
        //Do stuff if input is s || S
        Console.Write("end: ");
    }
}

I expect to be able to press 's' || 'S' and then type out a message, but depending on how long I have been waiting I may have to hold 's' for a long time.

The solution I happened across because of the first comment.

using System;
using System.Threading;

/// <summary>
/// Problem fixed I don't know why
/// Probably not making a new function for each call
/// </summary>
class Program
{
    static void Main(string[] args)
    {
        DontLockOnCharGet bug = new DontLockOnCharGet();
        bug.Setup();
    }
}
public class DontLockOnCharGet
{
    public void Setup()
    {
        while (true) { DontLockCharGet(); }
    }

    public void DontLockCharGet()
    {
        while (true)
        {
            //Specifies time to wait for input
            char i = Reader.ReadKey(1000);
            if (i == 's' || i == 'S')
            {
                //Do stuff if input is s || S
                break;
            }
            Console.Write(i);
        }
        // Do stuff
        Console.Write("end: ");
    }
}

class Reader
{
    private static Thread inputThread;
    private static AutoResetEvent getInput, gotInput;
    private static char input;

    static Reader()
    {
        //Setup once
        getInput = new AutoResetEvent(false);
        gotInput = new AutoResetEvent(false);

        //inputThread = new Thread(reader);
        //inputThread.IsBackground = true;
        //inputThread.Start();
    }

    private static void reader()
    {
        //waits for .Set()
        getInput.WaitOne();
        input = '\0';
        input = Console.ReadKey().KeyChar;
        //Marks if input is gotten
        gotInput.Set();
    }

    // omit the parameter to read a line without a timeout
    public static char ReadKey(int timeOutMillisecs = Timeout.Infinite)
    {
        //Setup and start read thread
        inputThread = new Thread(reader)
        {
            IsBackground = true
        };
        inputThread.Start();
        //Allows thread to continue in reader()
        getInput.Set();
        //Wait for input or back out befor it is given
        bool success = gotInput.WaitOne(timeOutMillisecs);
        return input;
    }
}

This version of code works as expected: Type 'S' and it auto-completes to "Send: "

  • It's pretty clear from the convoluted state of your code that whatever it is you're trying to do, you're going about it the wrong way. But...I can't really tell what it is you're trying to do. Your comment says _"the read keys stacking up"_, but I can't tell what that means. The code you posted should issue only a single `ReadKey()` call at a time, since the method blocks until there's a key press, and since you have only one thread calling it. Please fix your post so that it details _precisely_ what the user input and actions are, and what _precisely_ you are trying to accomplish. – Peter Duniho Jun 23 '19 at 04:51
  • Thanks @PeterDuniho I am pretty sure the problem was in the making a function for the Thread on each loop. – Cody Harkinz Jun 24 '19 at 15:37

1 Answers1

0

The problem is in the new Thread(()=> { ... }); This is creating a new function not just a new function call. The function being created should be moved into a separate function like this

private void ReadKey(){
        // Waits for getInput.Set()
        getInput.WaitOne();

        //The problem with this is the read keys stacking up
        // causing the need for a lot of keystrokes
        input = Console.ReadKey().KeyChar;

        gotInput.Set();
}

inside the class.

Make these

AutoResetEvent getInput, gotInput;
char input;

class variables and initialize them inside Setup(){...}

Finally call Thread tom = new Thread(ReadKey); where the new function is currently being made.

Note: This answer is not for best practice use, but will get a prototype to work.