C# Check for key press without delay (Console application) [duplicate] - c#

This question already has answers here:
Listen on ESC while reading Console line
(6 answers)
Closed 1 year ago.
first time posting here, so I apologise in advance in case I miss something important, please let me know if that's the case!
I'm writing a console application that has a menu with several different options in different layers, and I'm trying to make a function that will, at any time as the user works in these menus, notice if the Esc key is pressed. To make my code less cluttered I wrote a separate method that I can simply call at any point when I'm asking for input (like a choice, or entering information into a form, or such).
The problem I have is that it always cancels out the first key press. If a user enters a number to move in the menu, the number doesn't get entered, if they enter a name into a form the first letter is missing etc.
Is there a way around this?
The code currently looks like this;
public static void checkForEsc()
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Escape)
{
switch (currentUserisAdmin)
{
case true:
Menu.AdminMenu();
break;
case false:
Menu.CustomerMenu();
break;
}
}
}
Thanks in advance :)
Edit:
Might be worth adding that the code where this snippet gets called looks something like this, with very small variations;
Console.WriteLine($"1. Add a user\n2. Remove a user \n3. See user info \n \n9. Cancel");
Program.checkForEsc();
int response2 = CheckIfResponseInt(Console.ReadLine());

You need to write your own line editor instead of using Readline. It's described in the link below. You may need to add support for other control keys such as backspace or add a check that only numeric keys are being pressed.
Listen on ESC while reading Console line

Related

How do I get Input to read other keys and not just Up and Down

I saw some codes like this:
if (Input.GetKey(KeyCode.UpArrow))
and
if (Input.GetKey(KeyCode.UpArrow))
Wanted to know how do I put other keys, as in the case of the "a"
if (Input.GetKey(KeyCode.AArrow))
tried this code here however it gives an error, as I write?
When using KeyCode in comparison (like an if statement) you must call the specific keycode you want to compare the input to. Microsoft has documentation which provides the standard KeyCodes represented in System.Windows which most, if not all, external libraries call to.
So in this case you need to check for the A key specifically.
if (Input.GeyKey(KeyCode.A))
{
//code runs if and only if the input key is the A key
}
else if (Input.GetKey(KeyCode.Escape))
{
//code runs if and only if the input key is the ESC key.
}
Now if you want many possible inputs at a specific time you may not wish to use an if statement, but I would recommend trying this out first to see if you get better results.

How to get rid of the ReadKey() que if a person where to spam a key?

My console application uses ReadKeys thruout the code; if a person where to say click a key when an ReadKey is not active, it would to my speculation be added to a que of sorts, so when the code gets to the readKey it instantly goes on the previus keypress and continues as if that key was pressed.
Is there a way to fix this?
Edit: To clarify, axidental keypresses affect the ReadKeys that have not yet been run
You can check if there is any key available in the input stream and then read the next key.
A very good solution can be found here: Clear Console Buffer
Another similar solution here: https://newbedev.com/csharp-c-console-clear-input-buffer-code-example
// while there are characters in the input stream
while(Console.KeyAvailable)
{
// read them and ignore them
Console.ReadKey(false); // true = hide input
}
// Now read properly the next available character
Console.ReadKey();

Why do I get System.String [ ] in my code while debugging?

I am on my final project in c# for beginners, but I can't seem to get my list to work properly. It also closes automatically after being 'filled' with orders.
class Burgare
{
private string[] hamburger = new string[24];
private int no_burger = 0;
public void add_burger()//Ordering of burgers
{
Console.Clear(); //Clears console to make it look cleaner
while (true)
{
int Burger_option = 0;
do
{
Console.WriteLine("");// The options user can choose from
Console.WriteLine("Please choose burgers from our menu:");
Console.WriteLine("-------Burgers--------");
Console.WriteLine("1 Original One 109");
Console.WriteLine("2 Pig & Cow 109");
Console.WriteLine("3 Spice & Nice 109");
Console.WriteLine("4 Green One 109");
Console.WriteLine("0 Go back to main menu");
Console.WriteLine("----------------------");
Console.WriteLine("");
try //Making sure the user only picks what is on the menu
{
Burger_option = int.Parse(Console.ReadLine());
}
catch
{
Console.WriteLine("You can only choose what is on the menu!");
}
switch (Burger_option) //Depending on the number user presses on keyboard different burgers will be added to order
{
case 1:
Console.WriteLine("You've added the Original One to your order");
Console.WriteLine("If you're done press 0 to go back to the main menu");
hamburger[no_burger] = "Original One";
break;
case 2:
Console.WriteLine("You've added the Pig & Cow to your order");
Console.WriteLine("If you're done press 0 to go back to the main menu");
hamburger[no_burger] = "Pig & Cow";
break;
case 3:
Console.WriteLine("You've added the Spice & Nice to your order");
Console.WriteLine("If you're done press 0 to go back to the main menu");
hamburger[no_burger] = "Spice & Nice";
break;
case 4:
Console.WriteLine("You've added the Green One to your order");
Console.WriteLine("If you're done press 0 to go back to the main menu");
hamburger[no_burger] = "Green One";
break;
case 0: //Sends user back to main menu
Run();
break;
}
no_burger++; //Adds burger
} while (no_burger != 0);
if (no_burger <= 25) //Maximum number of orders
{
Console.WriteLine("The restaurant can't take more than 24 orders of burgers at the time");
Run(); //Sends user back to main menu when the order is over 24
}
}
}
public void print_order()
{
Console.WriteLine("-Your current order-");
foreach (var burger in hamburger) //Showing a list of what is in the order
{
Console.WriteLine(hamburger);
if (burger != null)
Console.WriteLine(burger);
else
Console.WriteLine("Empty space"); //Making empty space to show where you can add more burgers
}
}
After entering 24 orders I get the error "System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'" I've looked around a bit but still don't really understand how to fix my code. I'd like for it to return to the main menu after telling the user the order is full.
For my second problem the System.String [] problem, it appears when I enter the 'print_order'. It shows itself as
System.String []
Empty space
System.String []
Empty space
And so on. If possible I'd like to either remove it completely or at least replace it with 1,2,3...etc.
First off, please only post one question per question; you've described many problems here, but only actually asked one question. If you have multiple questions, post multiple questions.
Why do I get System.String[] in my code while debugging?
C# by default gives the name of the type when you print it out, and you're printing an array of strings. To turn an array of strings into a string, use the Join method of the string type. Be careful to not confuse it with the Join extension method on sequences.
It also closes automatically after being 'filled' with orders.
When a console program's control reaches the end of Main, it terminates the program. If you want something else to happen, write code that indicates what you'd like to happen.
After entering 24 orders I get the error "System.IndexOutOfRangeException: 'Index was outside the bounds of the array.'" I've looked around a bit but still don't really understand how to fix my code. I'd like for it to return to the main menu after telling the user the order is full.
You've reserved space for 24 things, and you've tried to access the 25th thing. That's a fatal error. Don't do that. You are required to detect that situation and prevent it.
If you want it to return to the main menu after telling the user the order is full then write code to do that. How? Since apparently the main menu is a thing that can happen more than once, you'll want to put it in a loop. You've already written two loops; put more stuff in the loops!
While we're looking at your code, some more good advice:
Start using the conventions of the C# language now. You wrote Console.WriteLine and then made a method print_order. Follow the pattern set by the designers of the framework, not something you've just made up on your own. Types and methods should be CasedLikeThis.
Never put an int.Parse in a try-catch, ever. That's what int.TryParse is for!
Your program has a bug; what happens if someone types in, say, 7? Handle that case!
You never actually check to see how many items you've added inside your do...while loop - you only check this after the loop is complete. That's why it crashes when you try to add the 25th item.
Move the logic to handle this inside your do...while loop and you won't get the exception anymore.
Also, your array only has room for 24 items, but I assume that you meant for it to be 25.
Also, since you're new to programming, you may want to look at #Eric Lppert's helpful article on debugging techniques - it'll save you a lot of time. You should also read about how to use a step debugger to diagnose problems.

ConsoleKeyInfo, the Question Mark and Portability

I have a little C# console application that reads a key and checks to see if the key was a question mark:
ConsoleKeyInfo ki = System.Console.ReadKey();
if (ki.ConsoleKey.Oem2) // Do something
I arrived at Oem2 by seeing what value is actually assigned in the debugger, because there is no ConsoleKey code for question mark.
Now I could certainly use ki.KeyChar instead, but the application also needs to respond to certain keys (e.g. media keys) that do not map to characters. It feels inelegant to check both ConsoleKey and KeyChar to determine which key has in fact been pressed. On the other hand, it does not feel safe to rely on Oem2 to always map to ? in all circumstances and regions.
Is it best practice to check both properties to determine which key was in fact pressed?
Any insight into why ConsoleKeyInfo was designed this way is appreciated.
In this case, you will have to check KeyChar == '?'. From MSDN:
Oem2: The OEM 2 key (OEM specific).
So you're just getting lucky in that it happens to be a ? on your equipment.
The ConsoleKeyInfo structure provides KeyChar (a Char value) as well as Modifiers (an enumeration) to help you decide what keys the user had pressed.
I think you should consider what happens when someone has different keyboard layout.
If you want to check for “the key with question mark on my computer”, then use ConsoleKey. But that's probably not a good idea and you should probably adhere to the user's settings and use KeyChar.
But for keys that don't map to to characters (and the user can't remap them by using different keyboard layout), you have to use ConsoleKey.
So, yes, I think you should check both properties in this case.
I guess the reason for this design is that Console.ReadKey() relies on a native function (ReadConsoleInput) that returns an array of KEY_EVENT_RECORD structures in case of a keypress, where each key event has an ASCII/Unicode character representation and a virtual key code. Notice the VK_OEM_2 in my previous link - this is where the ConsoleKey.Oem2 value comes from.

Capture any kind of keystrokes (aka keylogger), preferably c# .net but any kind will do [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I need to capture everything that I type on my keyboard and then store it in numerous ways. I'd prefer it to be written in C# for .Net, but anything will do really.
My reasons to write this "keylogger" are simple:
Recently I became an owner of a Peregrine gaming glove. It's a very cool thing that allows you to issue commands by making gestures with your fingers, and at the same time, its a very thin glove so you can type with that hand with little discomfort.
Also, I have found a nice program called AutoHotkey that can severely boost your productivity by making macros for like any action. You can bind any key to any other key or series of keys or commands.
The problem is, you cannot tell it just like that "this is what I'm doing most" and "this is what I'm rarely using." Really, can you tell what key do you use more, page down or down? Do you use alt+tab more frequently that escape or layout switch (ctrl-shift or alt-shift)? I cannot tell that. I cannot tell which actions should I automate or switch to the more easy interface, without statistical data.
So I want to write a program to run in the background and log everything I type. This program will then store first, second and third order histogram of my actions (like, it will store how many times I pressed any single key, like entering, how many times I pressed a succession of two keys, like alt and then tab, and how many times I pressed a succession of three keys, like ctrl, alt and then deleted or ctrl,shift and then escape)
Then, after some time spent working/playing/whatever, I'll have information on what kind of actions should I try to bind to that interface (the glove) or automate with AutoHotkey program, to improve the speed of interacting with a PC.
In other words, simple science experiment, just for fun and progress :)
Old question but...
In Windows you can use the APIs of the user32.dll.
For a very simple keylogger you can use the method GetAsyncKeyState() checking whether each character of the ASCII table is pressed.
The whole code for a very simple and stupid keylogger written in a Console Application would be:
[DllImport("user32.dll")]
public static extern int GetAsyncKeyState(Int32 i);
static void Main(string[] args)
{
while (true)
{
Thread.Sleep(100);
for (int i = 0; i < 255; i++)
{
int keyState = GetAsyncKeyState(i);
// replace -32767 with 32769 for windows 10.
if (keyState == 1 || keyState == -32767)
{
Console.WriteLine((char)i);
break;
}
}
}
KeystrokeAPI
For those who are looking for something more robust and cleaner I've created an API that makes it easy. You only need to do this:
api.CreateKeyboardHook((character) => { Console.Write(character); });
More details here: https://github.com/fabriciorissetto/KeystrokeAPI
You need a global keyboard handler.
If this is windows you will have to use the Windows API and use the following:
SetWndowsHookEx
UnhookWindowsHookEx
CallNextHookEx
You need to set up a global "hook" to listen for keyboard and mouse events.
I have a C# class that does this and raises .Net keyboard and mouse event args, but I am not going to post the code online as this type of activity can be used for nefarious means.
Why did we do this? We embedded powerpoint into our application, but we didn't want the user editing the powerpoint slides while viewing them so from our C# application we set up a hook to monitor and intercept mouse and keyboard events if they were in the powerpoint control. Worked great but we had to make sure:
They were in control in our application, our application was active, etc. Once you set up the hook, it listens/captures for everything including other applications, since we were canceling specific keyboard actions we only wanted it when we needed it.
Here's an API link.
http://msdn.microsoft.com/en-us/library/ff468842(v=VS.85).aspx

Categories