Pause after first keypress, synchronous solution - c#

There is the whole super simple C# console app here:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int left = 0;
Console.SetCursorPosition(++left, 0);
while (true)
{
ConsoleKeyInfo stisknutaKlavesa = Console.ReadKey(true);
if (stisknutaKlavesa.Key == ConsoleKey.RightArrow)
{
Console.SetCursorPosition(++left, 0);
Console.Write("#");
}
}
}
}
}
Description: When I press RIGHT KEY (and hold it!!) it quickly writes one hash, then there is a pause, and then it fluently keeps writting another hashes further.
How can I get rid of that pause? I have been dealing with identical problem in one of my winform app, but for simplicity I posted it in this console application here.
I have found some answers about this topic but all of them were about javascript (jquery) and i did not understand how to apply it on this my c# project.
And i do not want to resolve it in asynchronous way either. Is there such a solution, please?

This comes from the way that the windows console (and most other text-based inputs in Windows and other environments) behaves. If you put your cursor on any text input (like your browser's address bar, for instance), and press and hold an arrow key, you will see it move once, pause, and then start moving repeatedly with a much shorter pause.
In effect, your console's ReadKey registers keypresses based on some predefined behaviors of the operating system.
If you want to be able to detect and respond to someone holding a key down, you'll need to use a medium that gives you more low-level access to events like keydown and keyup. Something like Windows Forms, WPF, Unity... pretty much anything that's not Console.
Furthermore, if you want to respond to those key-down and key-up events using timing that's different from how the system treats those events, you'll have to create your own timing mechanism, and only use those events to help you know when things have changed. Examples of this can be found here and here.
If you're trying to make something akin to a video game, you might consider looking into libraries that are specifically designed for these use cases, like Unity3D.

Related

Migrate C# code from Console to Windows Form Application

I have been learning C# using the book "Programming in the Key of C#...", this book has been very good in helping me understand the language but only deals with Console programs. I am ready to move on to developing versions of my past coding projects as Windows form applications but one program in particular is causing me a lot of frustration. I developed a simple movie trivia program utilizing arrays to hold the questions, answer choices, and the correct answer. It worked by displaying on the console the questions, the possible answers and waited for the user to provide a response (basically A,B,C or D) by using Console.Readline() to assign the response.
Now I want to be able to have the user enter the answer by selecting 1 of 4 buttons (A through D). Based on my old code, I am unsure how I get the program to wait for the user to click one of the buttons. I assume i need to change the nature of the loops but I just cant figure out how. Any help would be much appreciated.
Here is a snippet of my Console code:
while (iAsked < 5)
{
iLocation = rand.Next(0, astrQuestions.GetLength(0));
if (list.Contains(iLocation))
rand.Next(0, astrQuestions.GetLength(0));
else
{
iAsked++;
list.Add(iLocation);
Console.WriteLine("Question {0}", iAsked);
Console.WriteLine("------------");
Console.WriteLine(astrQuestions[(iLocation)]);
Console.WriteLine(astrChoices[(iLocation)]);
Console.Write("Answer:");
iResponse = Console.ReadLine();
if (iResponse == astrAnswers[(iLocation)])
{
Console.WriteLine("Correct\n");
iPoints += 5;
iCorrect++;
}
else
{
Console.WriteLine("Incorrect\n");
}
}
Moving from a prompting-centric environment like a console program to an event-driven environment like Winforms, yes…that definitely will require at least some change in "the nature of the loops". :)
That said, the latest version of C# offers an async/await-based approach that can minimize some of the culture-shock that might come from moving from console to GUI. Writing and using async method is itself non-trivial, but IMHO the simpler scenarios are not too hard to understand. More importantly, because it allows you to structure the code in a more directly-imperative way, similar to that which would be used in a console program, it's very much worth learning this along with Winforms generally.
In your particular scenario, you have two separate things you'll need to deal with: prompting the user, and receiving the user's input.
Because of the way an event-driven system works, you need to separate these tasks. But .NET has a class, TaskCompletionSource, which we can use to keep the two glued together, even though they wind up in different places.
First, what happens when the user starts the process? Presumably, you'll have a form, where on that form is a button (or possible a menu item) which when clicked/selected, starts the whole thing. That might look something like this:
private TaskCompletionSource<bool> _completionSource;
private async void button1_Click(object sender, EventArgs e)
{
int[] questionIndexes = ShuffleQuestions();
for (int iAsked = 0; iAsked < 5; iAsked++)
{
textBoxQuestionNumber.Text = string.Format("Question {0}", iAsked);
textBoxQuestion.Text = astrQuestions[questionIndexes[iAsked]];
textBoxChoices.Text = astrChoices[questionIndexes[iAsked]];
_completionSource =
new TaskCompletionSource<bool>(astrAnswers[questionIndexes[iAsked]]);
button2.Enabled = true;
bool result = await _completionSource.Task;
MessageBox.Show(result ? "Correct" : "Incorrect");
if (result)
{
iPoints += 5;
iCorrect++;
}
button2.Enabled = false;
_completionSource = null;
}
}
private void button2_Click(object sender, EventArgs e)
{
if (_completionSource != null)
{
_completionSource.SetResult(
textBoxUserAnswer.Text == (string)_completionsSource.Task.AsyncState);
}
}
(I have changed your question-selection logic above to something more efficient, by assuming that you have a ShuffleQuestions() method. See Is using Random and OrderBy a good shuffle algorithm? for details on how to implement that).
What the above code does is, in response to the user clicking the button1 button (which presumably has text like "Start" or something), executes a loop that is very similar to what you had in your console program. The two main differences are:
Where in your console program, you use Console.WriteLine() to display text to the user, here I have shown the use of TextBox controls in your form which are used to display the same text.
What in your console program, you use Console.ReadLine() to receive input from the user, this loop creates a TaskCompletionSource object for a completely different method to use. That method, which is executed with your button2 button (which presumably has text like "Check Answer" or something) will read the text entered in a text box by the user (here, I've given it the name textBoxUserAnswer), compare it to the correct answer for the question (which has been provided to this method by the other method via the AsyncState property of the Task created by the TaskCompletionSource object I created), and set the Task's result to true or false, depending on whether the user got the answer correct or not.
The tricky part above is that "under the hood", that first method actually returns as soon as it is done filling in the text for the first question and reaches the await statement in the loop. The compiler rewrites the entire method to facilitate this.
When button2 is pushed, and sets the result of the Task, the framework then knows to resume executing the first method where it left off at the await statement, continuing your loop.
This sequence continues until the user has answered all of the question.
Some final notes about the UI:
I have used TextBox's everywhere for user input and output. Of course, there are other ways to display text. Also, the default state for a TextBox is a single-line, read/write text. But for displaying to the user, you may find that setting the ReadOnly property of the TextBox to true is better (i.e. to prevent the user from accidentally changing the text), and/or that you prefer setting the Multiline property to true (i.e. so that more than one line of text is displayed).
The above also assumes that the initial state for the button2 button's Enabled property is false. I.e. that button can't be clicked until the first method above explicitly enables the button at the appropriate time.

How do I fire up an event on any keyboard, mouse or gamepad state change?

Is there a way to immediately react to any change in the states of mouse, keyboard and gamepad(s) in a C# application?
I believe XNA is just like any other C# app, so it might not be any different, but just in case, I want to improve my XNA game input by immediately firing up corresponding events.
Default XNA doesn't have an event handler (at least I've never seen it being mentioned). Nuclex.Input doesn't detect some keys (like Alt, F10 or Pause, which is unacceptable).
Normally you store the state of the input on the previous frame, and then test whether then input has changed between frames. For example, your Update method might look like:
KeyboardState ks = Keyboard.GetState();
if(ks.IsKeyDown(Keys.Space) && lastKeyboardState.IsKeyUp(Keys.Space))
{
DoAThing();
}
lastKeyboardState = ks;
(Wrote that code entirely from memory, so it might not be quite right. But it should illustrate the concept.)
This will give you key events with no more than 1 / yourFPS delay. At 60FPS this is about 16ms. This is usually acceptable for gameplay purposes. If you especially want an event - you could simply fire one where I have put DoAThing, above.
For typing text you generally want the character events from Windows (which a library like Nuclex.Input can give you). This isn't so much so you get better latency, but so you can get keyboard events in an ordered and reliable way (for example: this way you never get two key coming down on a single frame resulting in an ambiguous order).
More importantly, it's so you can get the events after Windows has had a chance to apply input processing. For example, this gives you difference between typing an a and an A. Or someone entering a character with alt+numpad, or applying a diacritic. The downside is that you miss out on various non-text keys like, as you mention, Alt, F10, Pause, etc.
Finally, a quick read over Nuclex.Input reveals that it at least should provide the keys that you want - specifically IKeyboard.KeyPress and .KeyRelease. If it's not working, it could be a bug in Nuclex. Or something on your system is interfering with window messages.
One possible work-around might be to accept the latency on these missing keys by polling for them as well. The code to use polling as a seamless fall-back is probably fairly simple.

Trying to call another GUI method within a different method c#

I'm having a little trouble concisely describing what it is that I'm trying to do, which is hurting my ability to search for an answer. I'll try to be specific with my problem, if anyone could give a suggestion or point me in the direction of what to study, I'd greatly appreciate it.Tr
I'm trying to program a GUI version of the cardgame Dominion, where playing different cards will yield different results and choices. Many of these cards have similar starting choices (e.g. select a card from your hand and trash it/look at enemy hand), but different ending choices (e.g. upgrade that trashed card/give trashed card to another player). upon playing a card, the program looks for the unique numeric card code and begins executing code specific to that card.
Here's where I'm hung up:
I'd like to have more general methods that listen for user input INSIDE the unique card-code, but I keep getting errors. Ideally, I'd be able to do something like
for(int i = 0; i < totalPlayers; i++)
{
showEnemyHand(i);
}
or
for(int i = 0; i < totalPlayers; i++)
{
thiefEffect(i);
}
within a 'buttonclicked' event (the "play card" button, specifically.) The showEnemyHand(int) and thiefEffect(int) method would wait for user input, store responses, and then return right back to the for loop that it was called from, but its not as easy as I'd originally hoped.
I'm suffering most from not even knowing what it is that I should be searching for. I've been reading up on event handling and delegates, and I'm not sure that's what I need. Can anyone point me in the direction of what I need to learn, or maybe give me the topic of what I'm trying to solve so I can search for it a little easier? (of course, helping me solve it would be appreciated too =D)
Thanks a bunch!
Jake
Your solution would be fine for a command line based game, in a language with continuations/coroutines, or maybe in a multi-threaded application where showEnemyHand etc would block on user input. For a GUI-based game, an event driven architecture is really what would work best for you, so in principle I'd suggest learning more about it.
But if you really want to do that using a loop, I'd suggest then reading about threading and blocking calls. Once you understand the concepts, you should be able to:
Create a separate thread to host your loop;
Create a lock that will block execution until the user inputs something (see the example in the linked question);
Use that lock in your loop and on the callback for user input:
In the beginning of your loop, you wait on your lock;
When the user inputs something (which you'll detect using an event handler - see the docs for the particular GUI framework you're using) you save which action was chosen and frees the lock;
Your loop will automatically continue, reading the saved action and performing an iteration, until it reachs the same point again and waits for another user input.
Whether this method is easier or harder than coding your rules using the event driven logic, it's debatable. The same can be said about coroutines (though being less experienced with that, I can not opinate). The pointers I gave should help you get started though.

How to create IDLE -like functionality to WinForms application

I'd like to add "IDLE-like functionality" to C# WinForms application, but I don't quite have an idea how to do that and couldn't find anything useful with Google.
So basically I want interactive command line interface, where user could enter some Python code and execute it (not just expressions, should be possible to define new functions).
So, where to start? Are there any good tutorials or samples available?
If my memory serves me correctly there's a chapter on embedding Python in the book Python in a Nutshell. Perhaps you can find some useful information there, but since the book is not Windows specific, you may have to adapt it yourself.
I would setyp my WinForm like this: add 2 textboxes.
1: for output. Set the multiline property of the first to true, and make it read only.
2: for input. Use KeyUp Or KeyPress Event for e.g. the return key and use the text to do what you want: add command to output textbox, launch code against the engine and capture output of interpreter
This link (http://groups.google.com/group/ironpy/browse_thread/thread/5e61a944c7c94d4b/0cbf29ec0f5fbb64?pli=1) might give some answers about launching commands agains a python engine.
IronRuby comes with a command line interpreter. Doesn't IronPython also have one? If so, the source code would be a good start :)
Oh, and if it doesn't, be sure to look at the IronRuby interpreter, because both languages are based on the DLR and are therefore similar enough to learn from both.
Thru IronPython mailing list I found IronTextBox2, which is good example how things are done. It needs a little tweaking, to get it running, but otherwise is good solution.
Here go my most generic solution:
Point cursorPoint;
int minutesIdle=0;
private bool isIdle(int minutes)
{
return minutesIdle >= minutes;
}
private void idleTimer_Tick(object sender, EventArgs e)
{
if (Cursor.Position != cursorPoint)
{
// The mouse moved since last check
minutesIdle = 0;
}
else
{
// Mouse still stoped
minutesIdle++;
}
// Save current position
cursorPoint = Cursor.Position;
}
You can setup a timer running on 60000 interval. By this way you will just know how many minutes the user don't move the mice. You can also call "isIdle" on the Tick event itself to check on each interval.

Passing input to a state machine (c#)

I'll try to explain my scenario as best i can;
At each application tick I query the current state of the keyboard and mouse and wrap them in individual classes and data structures. For the keyboard it's an array of my Keys enum (one item for each of the keys that are currently pressed) and for the mouse it's a class containing coordinate delta's and bools for each buttons pressed.
I also have a rudimentary state machine managed via a state manager class which maintains the stack and marshalls the states.
All I want to know is, how best to pass the input (snapshots) to the individual states my app can be in at any one time?
I would like to process as much of the input as possible away from the individual states, so as to reduce repeating logic within the states.
Or would it be better to keep the input snapshots as pure as possible and pass them to the states so they can keep they're input-specific-logic hidden?
Note
This structure is similiar to how I imagine a game would work, and although this application is not a game it does need to be processed as quickly as possible.
Why are you querying the state of the keyboard and mouse with each tick? A much better and traditional solution would be to capture events fired from the keyboard and mouse. That way you only need to update the state when you HAVE to.
If you simply query your keyboard and mouse every tick, I can guarantee you'll run into problems. When you query every tick, you'll find that you miss inputs that occur quickly (within the time domain of a single tick). Imagine a situation where the user presses and releases a key/button between two ticks (it will happen more than you think) - you'll completely miss the input.
Particularly in C#, which is completely geared for input events like this, you should be using events.
In XNA, they do this by making the keyboard class static.
KeyboardState state = Keyboard.GetState();
you can then access the current key state with the above line of code.
You should fire events and capture the arguments. That would be the easiest, and most efficient way to handle this.
class YourClass
{
//data members ...
public void OnKeyboardPress(object sender, EventArgs args)
{
//handle your logic capturing the state here
}
}
//elsewhere
someControl.KeyPress += new KeyPressDelegate(yourClassInstance.OnKeyboardPress);

Categories

Resources