I am experimenting with keyboard input in SDL and I have encountered a strange problem. Whenever I get input it only outputs the appropriate response sometimes (Clicking X only sometimes closes the program, pressing 1 only sometimes outputs "you pressed 1". Here is my main code:
#include <iostream>
#include <SDL.h>
#include "Screen.h"
#include "Input.h"
using namespace std;
int main(int argc, char *argv[]) {
Screen screen;
Input input;
if (screen.init() == false) {
cout << "Failure initializing SDL" << endl;
}
while (true) {
if (input.check_event() == "1") {
cout << "You pressed 1" << endl;
} else if (input.check_event() == "quit") {
break;
}
}
SDL_Quit();
return 0;
and here is my Input class:
#include <iostream>
#include <SDL.h>
#include "Input.h"
using namespace std;
string Input::check_event() {
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
return "quit";
}
else if(event.type == SDL_KEYDOWN){
switch(event.key.keysym.sym){
case SDLK_1:
return "1";
}
}
}
return "null";
}
Any help would be appreciated!
From the documentation of SDL_PollEvent():
If event is not NULL, the next event is removed from the queue and
stored in the SDL_Event structure pointed to by event.
Analyzing your code:
if (input.check_event() == "1") {
This removes the event, whatever it is, from the queue.
} else if (input.check_event() == "quit") {
Say the return value of the 1st call to check_event() was "quit", then this call won't return "quit" again, because this information is now lost.
To fix that, call check_event() only once per loop iteration and store the result in a temporary variable. Then use only that variable in the conditions:
while (true) {
string event = input.check_event();
if (event == "1") {
cout << "You pressed 1" << endl;
} else if (event == "quit") {
break;
}
}
Related
By using GetAsyncKeyState it cannot detect '~' button (at the top left of the keyboard).
So there is any way to detect this button?
Or should I use another command ?
By the way I am using c++
The virtual key code of "~" is VK_OEM_3.
More virtual key codes can be referenced:
https://learn.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
How to use it, please refer to MSDN
A simple example:
#include <Windows.h>
#include <iostream>
using namespace std;
int main()
{
BOOL OEM_3 = FALSE;
while (1)
{
if (GetAsyncKeyState(VK_OEM_3) < 0 && OEM_3 == false)
{
//Press down
OEM_3 = true;
cout << "Press down" << endl;
}
if (GetAsyncKeyState(VK_OEM_3) >= 0 && OEM_3 == true)
{
//Release
OEM_3 = false;
cout << "Release" << endl;
}
}
return 0;
}
The below code expects the user to key in a character on every loop. If I want to keep running this loop without user having to enter any character on every loop till the number 0 is keyed in, how do i achieve it.
#include<iostream>
int main()
{
int i = 1;
int ch = 1;
while (ch != 0)
{
std::cin >> ch;
std::cout << "Hi" << i << std::endl;
++i;
}
return 1;
}
Threading is your only possibility. Also it always requires the ENTER when you are using std::cin. This could work:
#include <future>
#include <iostream>
#include <thread>
int main(int argc, char** argv) {
int i = 1;
std::atomic_int ch{1};
std::atomic_bool readKeyboard{true};
std::thread t([&ch, &readKeyboard]() {
while (readKeyboard) {
int input;
if (std::cin >> input) {
ch = input;
if (ch == '0') {
break;
}
}
}
});
while (ch != '0') {
std::cout << "Hi" << i << std::endl;
++i;
}
readKeyboard = false;
t.join();
return 1;
}
You can do this but you will have to use threads. Here is the minimal example how to achive this behaviour. Please note that you will need C++11 at least.
#include <iostream>
#include <thread>
#include <atomic>
int main()
{
std::atomic<bool> stopLoop;
std::thread t([&]()
{
while (!stopLoop)
{
std::cout << "Hi";
}
});
while (std::cin.get() != '0') //you will need to press enter after pressing '0'
{
; //empty loop, just wait until there is 0 on input
}
stopLoop = true; //this stops the other loop
}
Other options will be to dive into OS specific libraries. You must now that C++ doesn't have any kind of non-blocking I/O in standard library and for most time you will have to press <ENTER> to have any input in input stream (std::cin)
I'm a bit new to C++, so I beg your pardon for being a bit nooby.
Is there a function I can use to make the console pause until a specific key is pressed?
Example being:
#include <iostream>
using namespace std;
int main()
{
int i = 0;
if (specific key pressed) {
i = 1;
} else if (other key pressed) {
i = 2;
}
cout << i << endl;
return 0;
}
The console should output 1 if the right key is pressed, and 2 if another key is.
What you're trying to do is a bit more complex, C++ makes use of the cin stream where the input into the console is fed into your program. Where as a key-press event would be something the operating system would handle and would vary between operating systems. So using something like this would require the user to press enter/return for the input to be received by the program.
char key;
std::cin >> key;
if (key == 'a') {
std::cout << 1;
}
else {
std::cout << 2;
}
Find some answers here How to handle key press events in c++
Works on Windows only:
#include <iostream>
#include <vector>
#include <Windows.h>
char GetKey(std::vector<char> KeysToCheckFor)
{
while (true)
{
Sleep(1);
for (int i = 0; i < KeysToCheckFor.size(); i++)
{
if (GetKeyState(toupper(KeysToCheckFor[i])) < 0) { return KeysToCheckFor[i]; }
}
}
}
int main()
{
std::cout << "Press one of the keys: a,b,c\n";
char returnedkey = GetKey({ 'a', 'b', 'c' });
std::cout << returnedkey << " has been pressed!\n";
system("pause");
}
Just started working with classes in C++ and i'm an encountering a strange occurrence when requesting input from the user.
I have two outcomes the conditionals will accept in the getUserWantToPlay() member function: 'y' or 'n'. Otherwise, it will output a message requesting a proper response. I'm in a very early stage of the build and I was just doing some testing on this member function and I noticed that when I type "yes" or "no" it acts as if I typed 'y' or 'n'. Why is this happening?
Application Code
//implementation of TicTacToe
//Using classes this time
#include <iostream>
#include "TicTacToeClass.h"
int main()
{
//Assumes no play unless user decides they want to play and initializes game variable to TicTacToe class
bool play = false;
TicTacToe game;
play = game.getUserWantToPlay();
while(play == true)
{
std::cout << "Playing the game" << std::endl;
break;
}
return(0);
}
Class Implementation
//TicTacToe class implementation
//Leeroy Jenkins
#include "TicTacToeClass.h"
#include <iostream>
bool TicTacToe::getUserWantToPlay()
{
char response;
bool invalidResponse = true;
bool play = false;
while(invalidResponse == true)
{
std::cout << "Would you like to play a new game of TicTacToe? (y/n) " << std::endl;
std::cin >> response;
if(response == 'y')
{
invalidResponse = false;
play = true;
}
else if(response == 'n')
{
std::cout << "No Problem!";
invalidResponse = false;
}
else
{
std::cout << "Please input a proper response (y/n)" << std::endl;
}
}
return play;
}
I have an infinite loop to implement a custom CLI, as follows
while (1) {
getline(cin, _input);
_parse_cmd(_input);
}
I created a signal handler as follows:
BOOL WINAPI _consoleSignalHandler(DWORD CEvent) {
char mesg[128];
switch (CEvent)
{
case CTRL_SHUTDOWN_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_BREAK_EVENT:
if (_CLI_instance) {
cout << "Close Signal" << endl;
}
break;
case CTRL_C_EVENT:
cout << "Ctrl + C to be implemented" << endl;
break;
default:
return FALSE;
break;
}
return TRUE;
}
With this configuration, when I hit CTRL+C, the CLI prints the message "Ctrl + C to be implemented"and never waits for user input again. How can I solve this?
NOTE: parse_cmd is a generic command parser that executes simple actions
Edit :
Your problem is that in C++, when the getline function is interrupted, you have to manually clear the error state before next call. It is enough in your loop to write :
while (1) {
getline(cin, _input);
if (cin.fail() || cin.eof()) {
cin.clear(); // reset cin state
}
_parse_cmd(_input);
}
But beware: as you also filter Ctrl-Break, you loop could be hard to stop ...
TL/DR : Below are my first steps to this simple solution first in C idiom, next in C++ one, that only filter Ctrl-C and are killed on Ctrl-Break.
You can obtain easily the Ctrl-C interception with the signal function.
Here is an example of usage :
#include <stdio.h>
#include <signal.h>
void ctrl_c(int sig) {
fprintf(stderr, "Ctrl-C caught\n");
signal(sig, ctrl_c); /* re-installs handler */
}
int main() {
char buf[256];
void (*old)(int);
old = signal(SIGINT, ctrl_c); /* installs handler */
for (;;) {
if (fgets(buf, sizeof(buf), stdin) != NULL) {
printf("Got : %s", buf);
}
}
signal(SIGINT, old); /* restore initial handler */
return 0;
}
Ctrl-C is intercepted, Ctrl-Break kills the program.
Edit :
Old C version was straightforward. In C++ you have to clear flags in cin if getline was interrupted :
#include <iostream>
#include <string>
#include <csignal>
using namespace std;
void ctrl_c(int sig) {
cerr << "Ctrl-C caught" << endl;
signal(sig, ctrl_c); // re-installs handler
}
int main() {
string buf;
void (*old)(int);
old = signal(SIGINT, ctrl_c); // installs handler
for (;;) {
getline(cin, buf);
if (cin.fail() || cin.eof()) {
cin.clear(); // reset cin state
}
else {
cout << "Got" << buf << endl;
}
}
signal(SIGINT, old); // restore initial handler
return 0;
}
It's now correct C++ even if I do not use the Microsoft specific SetConsoleCtrlHandler. IMHO signal usage if more simple if only Ctrl-C has to be caught.