SDL 2.0 Keyboard Handling - c++

I am writing a very simple sample program that simply shows you "a key is pressed or not" only once, the key pressed event is triggered whenever i press any number of keys (either i press one key, two keys or more), while the key is released event is triggered when an SDL_KEYUP event is occurred while the number of keys pressed is only 1 key, this example works perfectly on arrow keys, however for the other keys whenever i press multiple keys and release only one of them a "Key is released" message is triggered followed by "a key is pressed", i failed to locate the problem with this.
my Code:
#include <iostream>
#include <SDL2/SDL.h>
using namespace std;
SDL_Event input;
int main(int argc, const char * argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
int y = 0;
int z = 0;
int w = 0;
bool key = false;
const Uint8 *state = SDL_GetKeyboardState(NULL);
while (1){
w = 0;
SDL_PollEvent(&input);
//check for events generated
switch (input.type) {
case SDL_KEYDOWN:
key = true;
break;
case SDL_KEYUP:
key = false;
break;
default:
break;
}
// Check for no. of keys pressed using ASCII code
for (y = 48;y<=127;y++)
if(state[y] == 1)
w++;
// Display the messages
if (key && z==0 )
{
cout << "Key is Pressed" << endl;
z = 1;
}
else if (!key && w < 1 && z==1)
{
cout << "Key is released" << endl;
z = 0;
}
}
return 0;
}

The problem was with the initialization of the for loop, SDL 2 does not use the same ASCII enumerations for characters thus my code tend to ignore the code enumerations outside the (48-127) range after changing the code to:
for (y = 0;y<=127;y++)
if(state[y] == 1)
w++;
the problem is solved

Related

Randomized Autoclicker C++ using one key for on/off

I have been attempting to write a cpp autoclicker using header <windows.h> but it isn't working the best. The code works fine and all, but its extremely annoying to turn off as it requires a millisecond click, nothing longer, if I hold that shortcut for too long, it turns back on again. Any suggestions for improvements?
#include <iostream>
#include <Windows.h>
#include <random>
using namespace std;
int counti;
void menu()
{
cout << "Press 'Ctrl + Tab' to enable and Press 'Ctrl + Tab' to disable randomised autoclicker\n";
}
void clicker()
{
bool click = false; //sets click to false
int n;
while (true)
{
while (1) {
n = rand() % 125;
if (n > 75)break;
}
if (GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(VK_TAB)) //if Ctrl + Tab is pressed
{
counti++;
if (counti % 2 == 1)click = true; //Shortcut pressed once and it activates
else if (counti % 2 == 0)click = false; //Shortcut pressed again and it deactivates
}
if (click == true) // if click = true it will press the mouse button down and up really fast
{
mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
cout << n << endl;
Sleep(n); //random speed here
}
}
}
int main()
{
menu();
clicker();
return 0;
}
Thank you!!
Don't use the same hotkey to turn on and off. Use a different key.

SDL2 cannot capture console keyboard events?

TL;DR
I am trying to capture keyboard events (more specifically, the Ctrl+c command) in my own C++ program. I am attempting this through generic keyboard presses in SDL2.
END TL;DR
I have found links on SO and the internet that cover the subject of handling keyboard events with SDL2. I have a few of them listed here.
https://stackoverflow.com/questions/28105533/sdl2-joystick-dont-capture-pressed-event
https://lazyfoo.net/tutorials/SDL/04_key_presses/index.php
http://www.cplusplus.com/forum/windows/182214/
http://gigi.nullneuron.net/gigilabs/handling-keyboard-and-mouse-events-in-sdl2/
The major issue I think is causing the problem is that I am also using an Xbox-style joystick at the same time. I have had no issues whatsoever with capturing joystick events. I have been doing that for a long time now. I am having issues trying to get anything with the keyboard to throw an event. I have tried if(event.type == SDL_KEYDOWN) and then checking which key it was, but that appears to return nothing. I feel like there is some macro that I need to define to allow this since I keep finding the same solutions on the internet.
I have included the entire script that I am running at the moment.
#include <boost/thread.hpp>
// Time library
#include <chrono>
// vector data structure
#include <vector>
// Thread-safe base variables
#include <atomic>
// std::cout
#include <iostream>
// Joystick library
#include <SDL2/SDL.h>
// Counters for printing
std::atomic_int printcounter{ 0 };
// This is every 3 * 1000 milliseconds
const int printer = 300;
// If an event is found, allow for printing.
std::atomic_bool eventupdate{ false };
// This function converts the raw joystick axis from the SDL library to proper double precision floating-point values.
double intToDouble(int input)
{
return (double) input / 32767.0 ;
}
// Prevent joystick values from going outside the physical limit
double clamp(double input)
{
return (input < -1.0) ? -1.0 : ( (input > 1.0) ? 1.0 : input);
}
// SDL library joystick deadband
const int JOYSTICK_DEAD_ZONE = 5000;
// These are the raw read in values from the joystick in XInput (XBox) mode.
//Normalized direction
int leftX = 0;
int leftY = 0;
int rightX = 0;
int rightY = 0;
int leftTrigger = -32768;
int rightTrigger = -32768;
// Button array
uint buttons[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Tbe pov hat is only 4 bits - 1, 2, 4, 8
int povhat = 0;
// These are the rectified joystick values
double leftstickx = 0;
double leftsticky = 0;
double rightstickx = 0;
double rightsticky = 0;
double lefttrigger = 0;
double righttrigger = 0;
// These are the rectified boolean buttons
bool leftstickbut = false;
bool rightstickbut = false;
bool xbutton = false;
bool ybutton = false;
bool abutton = false;
bool bbutton = false;
bool rightbut = false;
bool leftbut = false;
bool startbut = false;
bool backbut = false;
bool centbut = false;
// This is the boolean that controls running the robot.
std::atomic_bool quitrobot{false};
// Joystick values
static double joyvalues[6] = { 0, 0, 0, 0, 0, 0};
static bool joybuttons[11] = { false };
// Sleep function
void wait(int milliseconds)
{
boost::this_thread::sleep_for(boost::chrono::milliseconds{milliseconds});
}
// Now the main code
int main(int argc, char** argv)
{
// Now the robot goes through the looping code until a quit flag is set to true
while ( ! quitrobot)
{
// Now we look for an Xbox-style joystick
std::cout << "Looking for gamepad..." << std::endl;
while(true)
{
// Now the program waits until an Xbox-style joystick is plugged in.
// resetting SDL makes things more stable
SDL_Quit();
// restart SDL with the expectation that a jostick is required.
SDL_Init(SDL_INIT_JOYSTICK);
// SDL_HINT_GRAB_KEYBOARD
// check for a joystick
int res = SDL_NumJoysticks();
if (res > 0) { break; } // Here a joystick has been detected.
if (res < 0)
{
std::cout << "Joystick detection error: " << std::to_string(res) << std::endl;
}
// we don't want the program running super fast when detecting hardware.
wait(20);
}
// Now we check to make sure that the joystick is valid.
// Open the joystick for reading and store its handle in the joy variable
SDL_Joystick *joy = SDL_JoystickOpen(0);
if (joy == NULL) {
/* back to top of while loop */
continue;
}
// Get information about the joystick
const char *name = SDL_JoystickName(joy);
const int num_axes = SDL_JoystickNumAxes(joy);
const int num_buttons = SDL_JoystickNumButtons(joy);
const int num_hats = SDL_JoystickNumHats(joy);
printf("Now reading from joystick '%s' with:\n"
"%d axes\n"
"%d buttons\n"
"%d hats\n\n",
name,
num_axes,
num_buttons,
num_hats);
/* I'm using a logitech F350 wireless in X mode.
If num axis is 4, then gamepad is in D mode, so neutral drive and wait for X mode.
[SAFETY] This means 'D' becomes our robot-disable button.
This can be removed if that's not the goal. */
if (num_axes < 5) {
/* back to top of while loop */
continue;
}
// This is the read joystick and drive robot loop.
while(true)
{
// poll for disconnects or bad things
SDL_Event e;
if (SDL_PollEvent(&e)) {
// SDL generated quit command
if (e.type == SDL_QUIT) { break; }
// Checking for Ctrl+c on the keyboard
// SDL_Keymod modstates = SDL_GetModState();
// if (modstates & KMOD_CTRL)
// {
// One of the Ctrl keys are being held down
// std::cout << "Pressed Ctrl key." << std::endl;
// }
if(e.key.keysym.scancode == SDLK_RCTRL || e.key.keysym.scancode == SDLK_LCTRL || SDL_SCANCODE_RCTRL == e.key.keysym.scancode || e.key.keysym.scancode == SDL_SCANCODE_LCTRL)
{
std::cout << "Pressed QQQQ." << std::endl;
}
if (e.type == SDL_KEYDOWN)
{
switch(e.key.keysym.sym){
case SDLK_UP:
std::cout << "Pressed up." << std::endl;
break;
case SDLK_RCTRL:
std::cout << "Pressed up." << std::endl;
break;
case SDLK_LCTRL:
std::cout << "Pressed up." << std::endl;
break;
}
// Select surfaces based on key press
switch( e.key.keysym.sym )
{
case SDLK_UP:
std::cout << "Pressed Up." << std::endl;
break;
case SDLK_DOWN:
std::cout << "Pressed Up." << std::endl;
break;
case SDLK_LEFT:
std::cout << "Pressed Up." << std::endl;
break;
case SDLK_RIGHT:
std::cout << "Pressed Up." << std::endl;
break;
}
std::cout << "Pressed blah di blah blah please print me." << std::endl;
}
// Checking which joystick event occured
if (e.jdevice.type == SDL_JOYDEVICEREMOVED) { break; }
// Since joystick is not erroring out, we can
else if( e.type == SDL_JOYAXISMOTION )
{
//Motion on controller 0
if( e.jaxis.which == 0 )
{
// event happened
eventupdate = true;
// Left X axis
if( e.jaxis.axis == 0 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
leftX = 0;
}
else
{
leftX = e.jaxis.value;
}
}
// Right Y axis
else if( e.jaxis.axis == 1 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
leftY = 0;
}
else
{
leftY = e.jaxis.value;
}
}
// Left trigger
else if ( e.jaxis.axis == 2 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
leftTrigger = 0;
}
else
{
leftTrigger = e.jaxis.value;
}
}
// Right X axis
else if( e.jaxis.axis == 3 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
rightX = 0;
}
else
{
rightX = e.jaxis.value;
}
}
// Right Y axis
else if( e.jaxis.axis == 4 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
rightY = 0;
}
else
{
rightY = e.jaxis.value;
}
}
// Right trigger
else if( e.jaxis.axis == 5 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
rightTrigger = 0;
}
else
{
rightTrigger = e.jaxis.value;
}
}
}
}
else if ( e.type == SDL_JOYBUTTONUP || e.type == SDL_JOYBUTTONDOWN )
{
// now we are looking for button events.
if (e.jbutton.which == 0)
{
// event happened
eventupdate = true;
// buttons[e.jbutton.button] = e.jbutton.state;
if (e.jbutton.button == 0)
{
buttons[0] = e.jbutton.state;
}
if (e.jbutton.button == 1)
{
buttons[1] = e.jbutton.state;
}
if (e.jbutton.button == 2)
{
buttons[2] = e.jbutton.state;
}
if (e.jbutton.button == 3)
{
buttons[3] = e.jbutton.state;
}
if (e.jbutton.button == 4)
{
buttons[4] = e.jbutton.state;
}
if (e.jbutton.button == 5)
{
buttons[5] = e.jbutton.state;
}
if (e.jbutton.button == 6)
{
buttons[6] = e.jbutton.state;
}
if (e.jbutton.button == 7)
{
buttons[7] = e.jbutton.state;
}
if (e.jbutton.button == 8)
{
buttons[8] = e.jbutton.state;
}
if (e.jbutton.button == 9)
{
buttons[9] = e.jbutton.state;
}
if (e.jbutton.button == 10)
{
buttons[10] = e.jbutton.state;
}
if (e.jbutton.button == 11)
{
buttons[11] = e.jbutton.state;
}
}
}
else if ( e.type == SDL_JOYHATMOTION)
{
if (e.jhat.which == 0)
{
// event happened
eventupdate = true;
povhat = e.jhat.value;
}
}
}
// Now that we have read in the values directly from the joystick we need top convert the values properly.
leftstickx = clamp(intToDouble(leftX));
leftsticky = clamp(intToDouble(leftY));
rightstickx = clamp(intToDouble(rightX));
rightsticky = clamp(intToDouble(rightY));
lefttrigger = clamp(intToDouble(leftTrigger));
righttrigger = clamp(intToDouble(rightTrigger));
// rectify the buttons to become boolean values instead of integers.
abutton = buttons[0] > 0;
bbutton = buttons[1] > 0;
xbutton = buttons[2] > 0;
ybutton = buttons[3] > 0;
//
rightbut = buttons[4] > 0;
leftbut = buttons[5] > 0;
//
centbut = buttons[8] > 0;
startbut = buttons[7] > 0;
backbut = buttons[6] > 0;
//
leftstickbut = buttons[9] > 0;
rightstickbut = buttons[10] > 0;
// Transfer axis to the array.
joyvalues[0] = leftstickx;
joyvalues[1] = leftsticky;
joyvalues[2] = rightstickx;
joyvalues[3] = rightsticky;
joyvalues[4] = lefttrigger;
joyvalues[5] = righttrigger;
// We are using the "B" button to quit the program
if (bbutton)
{
quitrobot = true;
std::cout << "Shutting down program." << std::endl;
break;
}
if (eventupdate)
{
// This section of code is meant for running code that happens when SDL has detected an event.
// This code section can be used for something else as well.
if (e.key.keysym.sym == SDL_SCANCODE_RCTRL || e.key.keysym.sym == SDL_SCANCODE_LCTRL || e.key.keysym.sym == SDLK_LCTRL || e.key.keysym.sym == SDLK_RCTRL)
{
std::cout << "SDL Event: Ctrl pressed.\n" << std::endl;
}
// Simply print the event
eventupdate = false;
} else {}
if ( ! (printcounter = ((printcounter + 1) % printer)))
{
// const Uint8 *state = SDL_GetKeyboardState(NULL);
// if (state[SDL_SCANCODE_RETURN]) {
// printf("<RETURN> is pressed.\n");
// }
}
// Sleep the program for a short bit
wait(5);
}
// Reset SDL since the robot is no longer being actuated.
SDL_JoystickClose(joy);
// We get here only if the joystick has been disconnected.
std::cout << "Gamepad disconnected.\n" << std::endl;
}
// The program then completes.
return 0;
}
The most important part of that huge block of code is lines 129 to 179. I was doing more fooling around trying to get key capture to work but I could not get a response. Everywhere else is logic for the joystick reading (which has worked for me flawlessly). I have been referring to this link for all of the macros available to the programmer. I have not been able to capture the left control button or the right control button. I have also been trying the arrow keys for kicks as well and those are not working either. I know there are remnants of other code snippets thrown in there as I was testing. Given all of my testing, I am just not sure how to capture any keyboard keys, let alone Ctrl+c. None of my desired print statements print.
I am able to run the code on Ubuntu 1804 LTS with the stock GUI manager and window manager. I have a feeling the problem might also have something to do with the operating system not letting SDL2 capture the keyboard, but I don't know what to do to allow only the keyboard or certain keys to be consumed by SDL2.
I am trying to not use platform-specific code since I already have successfully used platform-specific signal interrupts. My goal is to simply make a certain combination of depressed keys result in a program terminating. I figured that, since SDL2 can access all keys on a keyboard, that I should be able to simply
Unless you want to read keyboard input from stdin you need to open a window and focus it to get key events in SDL. Here's an example (note the call to SDL_Init uses SDL_INIT_VIDEO and there's some code in there for rendering a background and handling resize events).
#include <iostream>
#include <SDL2/SDL.h>
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0) { // also initialises the events subsystem
std::cout << "Failed to init SDL.\n";
return -1;
}
SDL_Window *window = SDL_CreateWindow(
"Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
680, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if(!window) {
std::cout << "Failed to create window.\n";
return -1;
}
// Create renderer and select the color for drawing.
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);
while(true)
{
// Clear the entire screen and present.
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT) {
SDL_Quit();
return 0;
}
if(event.type == SDL_WINDOWEVENT) {
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
int width = event.window.data1;
int height = event.window.data2;
std::cout << "resize event: " << width << "," << height << std::endl;
}
}
if (event.type == SDL_KEYDOWN) {
int key = event.key.keysym.sym;
if (key == SDLK_ESCAPE) {
SDL_Quit();
return 0;
}
std::cout << "key event: " << key << std::endl;
}
}
}
return 0;
}
Key events are sent to the currently focused window and SDL uses the underlying OS to handle this. E.g. In Linux this means SDL calls X11 functions.
edit:
As detailed in this question it appears you can also get a snapshot of the state of the keys. In either case I think a window needs to be opened to receive events even though I've edited this multiple times to come to that conclusion (apologies if that caused any confusion). Your OS may provide functions for polling the state of the keyboard without using events or windows, such as GetAsyncKeyState in Windows.

Enter and Exit menu using enum and switch sfml

In my game right now I am trying to make a menu you can access when you press 'q', but currently I am having some issues. I think it switches to the CompScreen view and then back to the currentroom view quickly, I may be wrong. I am getting the cout CompMenu, HELP, and hello readings so I know it is running through the programs, but when I press q I remain in the same spot, nothing happening.
EventManager.h
#ifndef EventManager_h
#define EventManager_h
#endif /* EventManager_h */
int windowWidth = 5000;//width of window
int windowHeight = 5000;//height of window
sf::View leveltwo(sf::FloatRect(x, y, 5000, 5000));
sf::View start(sf::FloatRect(0, 0, 2500, 1500));
sf::View ComputerScreen(sf::FloatRect(50000, 50000, 5000, 5000));
sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight ), "Awesome Game" );
Character player("/Users/danielrailic/Desktop/Xcode /NewGame/ExternalLibs/Sprites/Player.png");
bool InMenu = false;
enum Levels{
StartRoom, LevelTwo
};
Levels room = StartRoom;
int currentroom;
void WhatRoom(int TheLevel){
switch (room){
case StartRoom:
currentroom = 1;
window.setView(start);
if (TheLevel == 2){
room = LevelTwo;
}
break;
case LevelTwo:
currentroom = 2;
window.setView(leveltwo);
break;
}
};
enum States{
compmenu, mainmenu, NoMenu
};
States menu = NoMenu;
void CompMenu(){
window.setView(ComputerScreen);
cout << "HELP";
InMenu = true;
}
void WhatMenu(int TheMenu){
switch (menu){
case compmenu:
cout << "CompMenu";
CompMenu();
break;
case mainmenu:
break;
case NoMenu:
if (TheMenu == 2){
menu = compmenu;
}
break;
if (TheMenu == 3){
menu = mainmenu;
}
break;
}
}
main.cpp (inside int main)
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q) and InMenu == false){
WhatMenu(2);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q) and InMenu == true){
InMenu = false;
WhatRoom(currentroom);
cout << "hello";
}
If you have any questions or need to see more of the code let me know. Thanks.
I think you've missed else after first if block so it may be executed immediately because InMenu may be changed to true at that point:
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q) and InMenu == true){
Also you should handle the situation when key is pressed for a long time (to react only when it enters pressed state) and get rid of all the global variables because they are already creating quite a mess.

SDL Text Input returning white squares

I created an event class and wanted to get text with it. Unfortunately the text isn't reading correctly...
I've set it up so that all text that is gotten is output to the command line when a new key is input, but it obviously isn't working.
Here's my "EventManager" code for my update function:
void EventManager::update(){
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN:
mousePressed = true;
break;
case SDL_KEYDOWN:
if(shouldCollectText && e.key.keysym.sym == SDLK_BACKSPACE && currentCollectedText.length() > 0){
currentCollectedText.pop_back();
}else if(shouldCollectText && e.key.keysym.sym != SDLK_BACKSPACE){
currentCollectedText += e.text.text; //The problem
std::cout << currentCollectedText << std::endl;
}
}
}
}
I followed the Lazy Foo tutorials, and I can't find the problem.
Some other things to note:
I start text input in my "main.cpp" class:
int main( int argc, char *argv[] ) {
Game *game = new Game();
game->init();
SDL_StartTextInput();
while(game->isRunning()){
game->handleEvents();
game->update();
game->render();
}
game->close();
SDL_StopTextInput();
return 0;
}
I create some of my variables in "EventManager.h":
bool shouldCollectText;
std::string currentCollectedText;
And define them in an "init()" function:
shouldCollectText = false;
currentCollectedText = "";
Your problem is that you are using the wrong event type. Take a second look at Lazy Foo's tutorial and here:
TextInputEvent
e.text.text is reserved for Text Input events and nothing else. Being SDL_Event an union of structures, overlaps may occur in the used memory. That is exactly what you see in the terminal output.
Remove the SDL_KEYDOWN event and try this instead:
case SDL_TEXTINPUT:
currentCollectedText += e.text.text;
break;
I'm not sure about std::cout << currentCollectedText << std::endl; though. It depends on when you want to get output of the text content.
If you want to use SDL_KEYDOWN you will have to access the keysym tables and maybe calculate to which letter they correspond and print those out. I would say, that approach is more complicated for what you want to achieve.
So in conclusion e.text.text will only work if e.type has the SDL_TEXTINPUT value as event. With all the other settings in your code that event should be triggered and may get the text you type in.
So your complete example could look like this:
void EventManager::update(){
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN:
mousePressed = true;
break;
case SDL_TEXTINPUT:
if(shouldCollectText && currentCollectedText.length() > 0){
currentCollectedText.pop_back();
}else if(shouldCollectText) {
currentCollectedText += e.text.text; //The problem
std::cout << currentCollectedText << std::endl;
}
break;
default: break;
}
}
}

Scrolling menu in the console

There is the menu in the console navigating by arrows UP-DOWN. Problem: when I select "Enter number" and the result disappears, I can't select another menu item. How to fix it?
Here is my C++ code:
#include <iostream>
#include <string>
#include <windows.h>
using namespace std;
int main()
{
string Menu[2] = {"Enter number", "Exit"};
int pointer = 0;
while(true)
{
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
cout << "Main Menu\n\n";
for (int i = 0; i < 2; ++i)
{
if (i == pointer)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 11);
cout << Menu[i] << endl;
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15);
cout << Menu[i] << endl;
}
}
while(true)
{
if (GetAsyncKeyState(VK_UP) != 0)
{
pointer -= 1;
if (pointer == -1)
{
pointer = 1;
}
break;
}
else if (GetAsyncKeyState(VK_DOWN) != 0)
{
pointer += 1;
if (pointer == 2)
{
pointer = 0;
}
break;
}
else if (GetAsyncKeyState(VK_RETURN) != 0)
{
switch (pointer)
{
case 0:
{
int number;
cout << "\nEnter number --> ";
cin >> number;
cout << "\nThe number is ";
cout << number;
Sleep(1000);
} break;
case 1:
{
return 0;
} break;
}
break;
}
}
Sleep(150);
}
return 0;
}
Maybe, it will be better to use Qt::Key instead of GetAsyncKeyState?
The problem is GetAsyncKeyState,
MSDN tells us:
If the function succeeds, the return value specifies whether the key
was pressed since the last call to GetAsyncKeyState, and whether the
key is currently up or down. If the most significant bit is set, the
key is down, and if the least significant bit is set, the key was
pressed after the previous call to GetAsyncKeyState.
So in your case, you pressed Enter to get your number, so the enter key has been pressed since the last call, so (GetAsyncKeyState(VK_RETURN) != 0) is always true.
You should have look more precisely on the return of GetAsyncKeyState to see if the key is really pressed, or to do nothing if the key was already pressed in the call just before. Be careful with the last option, other apps or threads can also call GetAsyncKeyState.
The reason why your result disappears when you select "Enter Number" is because you reinitialize the output buffer with the new string every time you press the "Up Arrow". You can get around this by turning this into a FSM logic where you are in control of the states and your next state is dependent on the current and previous state. At the moment, your logic only cares about the current state.
To be sure to test if a key is pressed at a moment, use:
short result;
result = GetAsyncKeyState(VK_RETURN);
if (result & 0x8000) { ... }
or
if (GetAsyncKeyState(VK_RETURN) & 0x8000) { ... }
I tried this at home but it seems Javia1492 is right, you also have a buffer problem I didn't know. Try not to use "system("cls")", it's old C. try to write your own clearing function like the following found on MSDN:
void cls( HANDLE hConsole )
{
COORD coordScreen = { 0, 0 }; // home for the cursor
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD dwConSize;
// Get the number of character cells in the current buffer.
if( !GetConsoleScreenBufferInfo( hConsole, &csbi ))
{
return;
}
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
// Fill the entire screen with blanks.
if( !FillConsoleOutputCharacter( hConsole, // Handle to console screen buffer
(TCHAR) ' ', // Character to write to the buffer
dwConSize, // Number of cells to write
coordScreen, // Coordinates of first cell
&cCharsWritten ))// Receive number of characters written
{
return;
}
// Get the current text attribute.
if( !GetConsoleScreenBufferInfo( hConsole, &csbi ))
{
return;
}
// Set the buffer's attributes accordingly.
if( !FillConsoleOutputAttribute( hConsole, // Handle to console screen buffer
csbi.wAttributes, // Character attributes to use
dwConSize, // Number of cells to set attribute
coordScreen, // Coordinates of first cell
&cCharsWritten )) // Receive number of characters written
{
return;
}
// Put the cursor at its home coordinates.
SetConsoleCursorPosition( hConsole, coordScreen );
}