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");
}
Related
I'm wondering how could I trigger a function when control + c is pressed but I want it not only in the program window but outside the window like in a browser, text pad and etc. Help would be appreciated.
This would be in C++
Thanks
You can do something like this on Windows:
char input = _getch();
if (input == '\x3')
{
std::cout << "Ctrl C pressed!" << std::endl;
//...
}
The above code will print "Ctrl C pressed!" when input == '\x3' (Control C).
Full example:
#include <iostream>
#include <conio.h>
void foo(char character)
{
std::cout << character << std::endl;
}
int main()
{
while (true)
{
char input = _getch();
if (input == '\x3')
{
foo(input);
}
}
}
I am making a game console with C++, I have a problem. When I press SPACE, my car in my game will jump. When I press and hold keyboard, my car will jump many times. I want: when I hold SPACE keyboard my car just jump once.
How to do this ?
I have read many topics about GetAsyncKeyState() but I don't know how to use it for my game.
if ( _kbhit() )
{
char key = _getch();
if ((key == 75) && (car.position.x > 2))
{
car.position.x -= 3;
}
else if ((key == 77) && (car.position.x < 24))
{
car.position.x += 3;
}
else if ((key == 32) && (car.position.y > 2))
{
car.position.y -= 5;
}
}
Below I have an example software of one possible way to 'filter' duplicate space chars out of an input stream.
The idea relies on the use of two threads.
Thrd1 reads from a stringstream called ssIn. (Replaced with cin in your code.)
Thrd1 (a filter) detects and discards back-to-back space chars, and only sends the first (of multiple space chars) to thrd2.
Thrd2 - reads from the single char buffer filled by thrd1 which will never see back-to-back space characters.
The 2 thrds are synchronized by a pair of semaphores (not mutex).
In my example, for my convenience, I used my version of a Posix semaphore. I do not know if you have Posix, but I am confident you will easily find many example C++ semaphores available on the web, even within SO, and most using only C++ features.
Note that this is only 1 test ... the alphabet with 1,000,000 spaces injected after 'j'. This is not a thourough test. There probably will be other issues to deal with. I have installed a harsh handling of input mis-behaviour. The assert will help you identify the issues.
"thrd2" represents your toe-hold into this example. Thrd2 receives the filtered stream.
#include "../../bag/src/dtb_chrono.hh"
using namespace std::chrono_literals; // support suffixes like 100ms, 2s, 30us
using std::chrono::duration_cast;
#include <iostream>
using std::cout, std::flush, std::endl;
//using std::cin;
#include <thread>
using std::thread, std::this_thread::sleep_for;
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
// Posix Process Semaphore, local mode, unnamed, unlocked
#ifndef DTB_PPLSEM_HH
#include "../../bag/src/dtb_pplsem.hh"
using DTB::PPLSem_t;
#endif
// string ops
#ifndef DTB_SOPS_HH
#include "../../bag/src/dtb_sops.hh"
using DTB::SOps_t;
#endif
#include <cassert>
namespace DTB
{
class T946_t
{
public:
int operator()(int argc, char* argv[]) // functor entry
{ return exec(argc, argv); }
private:
// uses compiler provided default ctor and dtor
// Posix Process Semaphore, local mode (unnamed, unshared)
// initial value unlocked
PPLSem_t th1Sem;
PPLSem_t th2Sem;
char kar = '\n';
bool done = false;
size_t m_rdy;
thread* th1;
string th1Log;
thread* th2;
string th2Log;
stringstream ssIn; // debug - replaces cin
stringstream ss1DR; // th1 delay'd report
stringstream ss2DR; // th2 delay'd report
// utilities
SOps_t sops; // string ops - digiComma
int exec(int , char** )
{
// test init: insert a possible user input into ssIn
init_ssIn();
int retVal = 0;
Time_t start_ns = HRClk_t::now();
th1Sem.lock(); // block until threads are ready
th2Sem.lock(); // block
// start ---------vvvvvvvvvvvvvvvvvvv
th1 = new thread(&T946_t::thrd1, this);
assert(nullptr != th1);
while (0 == (m_rdy & 0x01))
std::this_thread::sleep_for(10ms);
// start ---------vvvvvvvvvvvvvvvvvv
th2 = new thread(&T946_t::thrd2, this);
assert(nullptr != th2);
while (0 == (m_rdy & 0x02))
std::this_thread::sleep_for(10ms);
th1Sem.unlock();
// spin wait for threads to complete
while (!done)
{
std::this_thread::sleep_for(100ms);
}
th1->join();
th2->join();
cout << "\n join()'s complete";
auto duration_ns = duration_cast<NS_t>(HRClk_t::now() - start_ns).count();
cout << "\n T901_t::exec() duration "
<< sops.digiComma(duration_ns) << " ns" << endl;
// output the delay'd reports
cout << ss1DR.str() << ss2DR.str() << endl;
return retVal;
}
void init_ssIn()
{
ssIn << "abcdefghij";
for (int i=0; i<1000001; ++i) ssIn << ' ';
std::string::size_type k = ssIn.str().size();
ssIn << "klmnopqrstuvwxyz";
// a..j
cout << "\n ssIn: '" << ssIn.str().substr(0, 10)
<< " ...spaces... " << ssIn.str().substr(k, 16) << "'"
<< "\n ssIn.str().size(): "
<< sops.digiComma(ssIn.str().size()) << endl;
}
void thrd1()
{
uint64_t th1Count = 0;
uint64_t th1Skips = 0;
char lkar = '\0';
m_rdy |= 0x01; // sync msg to main
do {
getNextKar(lkar); // read from input (ssIn or cin)
th1Sem.lock(); // wait for thrd2 to give permission
{
if(' ' == lkar) // current input kar
{
if(' ' == kar) // previous kar
{
// filter out back-to-back space chars
th1Skips += 1;
th1Sem.unlock(); // skip the handshake, no char to send,
// give self permission-to-proceed
continue;
}
}
// else, not a duplicate space
th1Count += 1;
kar = lkar; // write to input of thrd2
th1Log += lkar; // log
lkar = ' ';
}
th2Sem.unlock(); // give thrd2 permission-to-proceed
if (ssIn.eof())
{
done = true;
break;
}
}while(!done);
ss1DR
<< "\n th1Count " << sops.digiComma(th1Count)
<< "\n th1Skips " << sops.digiComma(th1Skips)
<< "\n th1Log " << th1Log
<< "\n thrd1 exit " << endl;
}
// read from ssIn for development
// read from cin for app
void getNextKar(char& lkar)
{
// ssIn >> lkar; // reads 1 char, but skips multiple blank chars
// lkar = ssIn.get(); returns an integer (not a char)
(void)ssIn.get (lkar);
if(ssIn.fail())
{
if(ssIn.eof()) return; // not a fail
assert(0); // harsh exit, might want something gentler
}
}
void thrd2()
{
uint64_t th2Count = 0;
m_rdy |= 0x02; // sync msg to main
do {
th2Sem.lock(); // wait for thrd1 to give permission
char t = kar;
th1Sem.unlock(); // give permission-to-proceed to thrd1
// simulate application - no duplicate spaces from input
th2Log += t;
th2Count += 1;
// end of sim
}while(!done);
ss2DR
<< "\n th2Count " << sops.digiComma(th2Count)
<< "\n th2Log " << th2Log
<< "\n thrd2 exit " << endl;
}
}; // class T946_t
} // namespace DTB
int main(int argc, char* argv[]) { return DTB::T946_t()(argc, argv); }
The output looks like:
ssIn: 'abcdefghij ...spaces... klmnopqrstuvwxyz'
ssIn.str().size(): 1,000,027
join()'s complete
T901_t::exec() duration 120,421,582 ns
th1Count 28
th1Skips 1,000,000
th1Log abcdefghij klmnopqrstuvwxyz
thrd1 exit
th2Count 28
th2Log abcdefghij klmnopqrstuvwxyz
thrd2 exit
The duration is 120 ms for 1 Million chars input.
As #Remy Lebeau pointed out you can get the repeat count by install WH_KEYBOARD hook and filter the key held pressed in KeyboardProc.
Of course, for simple, no need install a hook you can filter repeat WM_KEYDOWN messages in window procedure when you press the space key and hold. The following is an example you can refer to:
case WM_KEYDOWN:
if (wParam == VK_SPACE)
{
if (!((HIWORD(lParam) & 0x4000) || (HIWORD(lParam) & 0x8000)))
{
isKeyHold = TRUE; // First time pressed
OutputDebugString(TEXT("pressed !\n"));
}
else if (isKeyHold && (HIWORD(lParam) & 0x4000))
{
OutputDebugString(TEXT("hold !\n"));
return 1; // Don't handle the message when the key is pressed and held.
}
}
break;
case WM_KEYUP:
if (wParam == VK_SPACE && isKeyHold)
{
isKeyHold = FALSE; // Clear the isKeyHold flag when release the key.
OutputDebugString(TEXT("release !\n"));
}
break;
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 am trying to do an implementation of htop (system monotitoring) in c++.
So I am using ncurses to refresh my terminal.
I need to get new info every 5 seconds for example, im using a loop to do so.
while (42)
{
key = std::cin.get();
std::cout << key;
this->gereEvent(key);
std::cout << i<< std::endl;
if (i == 500000000)
{
std::cout << "test"<< std::endl;
// fputs(tgetstr((char *)"cl", 0), stdout);
this->refresh();
i = 0;
}
i++;
}
But problem is cin.get() stops the loop..
I cannot do a thread eitheir because std::thread needs c++11.
Have you an idea of how I can do that ?
You need to poll the keyboard events. This can be done in ncurses with getch.
#include<stdio.h>
#include<curses.h>
#include<unistd.h>
int main ()
{
int i=0;
initscr(); //in ncurses
timeout(0);
while(!i)
{
usleep(1);
i=getch();
printw("%d ",i);
if(i>0)
i=1;
else
i=0;
}
endwin();
printf("\nhitkb end\n");
return 0;
}
This example is from http://cc.byexamples.com/2007/04/08/non-blocking-user-input-in-loop-without-ncurses/comment-page-1/#comment-2100.
I need to have a while-loop running and accept input to it whenever there is an input. I'm not new to C++, but this hurdle is quite difficult. Due to an NDA (this school project is apparently some secret stuff) I can only show you the test case.
I've been grasping for straws trying to solve the problem; try catch, cin.get, cin.peek, if(cin.peek){}. If anybody can point me in the right direction I would be very grateful!
The program is not time-critical, but a function needs to be called with a fixed interval. It is not essential that the code is portable, that it is a while-cin-combination or anything like that; the code will only ever run on a Windows 7 or Windows 8 PC with at least dual core processor.
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
int input = 0;
int pastTime, nowTime;
pastTime = nowTime = time(0);
cin >> input;
while(input != -1)
{
if(input == 1)
{
cout << "Entered 1" << endl;
//To be done instead of the two 'elses',
//bypassing interval-dependant code
}
else if(input == 2)
{
cout << "Entered 2" << endl;
//To be done instead of the interval-dependant code
}
else if(pastTime == (nowTime - 5))
{
cout << "Nothing entered." << endl;
//Needs to be done with a fixed interval.
}
nowTime = time(0);
cin >> input;
}
return 0;
}
The solution was, based om James Beilby's link:
// This program is based on counter.cpp from Boost\lib\thread\tutorial
#include <boost/thread/thread.hpp>
#include <iostream>
#include <ctime>
int timeNow = time(0);
int timePast = time(0);
void fct_one()
{
while(1) //keeps running all the time
{
if(timePast == (timeNow - 3)) // only executed once every three seconds
{
//do some stuff
timePast = time(0);
}
timeNow = time(0); // time is continuously updated
}
}
void fct_two()
{
int input = 0;
int timeTemp = time(0);
while(1) //keeps running all the time
{
std::cin >> input; // cin blocking for input
if(input == 1)
{
//do some stuff
}
if(input == 2)
{
//do some stuff
}
if(input == -1)
{
std::cout << "Program is done. ";
system("pause");
exit(1);
}
}
}
int main()
{
boost::thread_group threads;
threads.create_thread(&fct_one)
threads.create_thread(&fct_two);
threads.join_all();
return 0;
}
I would completely separate reading input from cin and performing the default timeout function. You'll need something like a background thread that performs the default function based on the time interval. To handle the 1st two cases you'll need to signal the thread skipping the next execution (if this is really necessary), and just call any function you want or do nothing.
The simple answer is to put the code that runs at some interval on another thread. Since you've noted this is Windows, you could use a Timer Queue:
Begin with routines to start and stop your time dependent work:
HANDLE Start(HANDLE hTimerQueue)
{
DWORD timerMS = 5000; /* every 5 seconds */
HANDLE hTimer;
if (!CreateTimerQueueTimer(&hTimer,
hTimerQueue,
(WAITORTIMERCALLBACK)timerWork,
/*lpParam*/NULL,
/*start in ___ ms:*/0,
/*run every __ ms:*/timerMS,
/*flags*/0))
{
return NULL;
}
return hTimer;
}
BOOLEAN Stop(HANDLE hTimerQueue, HANDLE hTimer)
{
if (!DeleteTimerQueueTimer(hTimerQueue,
hTimer,
/*wait for our timer to complete*/INVALID_HANDLE_VALUE))
{
return FALSE;
}
return TRUE;
}
Then put your time dependent work into its own callback:
VOID CALLBACK timerWork(PVOID lpParam, BOOLEAN TimerOrWaitFired /*ignored*/)
{
for (int ii = 0; ii < 10; ++ii) {
std::cout << "timer work: " << ii << std::endl;
Sleep(250);
}
}
Finally, integrate these into your workflow:
int main(int argc, char* argv[])
{
HANDLE hTimerQueue = CreateTimerQueue(hTimerQueue);
if (NULL == hTimerQueue) return -1;
HANDLE hTimer = Start(hTimerQueue);
if (NULL == hTimer) return -1;
/* our timed callback is now running in the background */
int input = 0;
std::cin >> input;
while(input != -1)
{
if(input == 1)
{
if (Stop(hTimerQueue, hTimer)) {
std::cout << "Entered 1" << std::endl;
if (NULL == (hTimer = Start(hTimerQueue))) return -2;
}
}
else if(input == 2)
{
if (Stop(hTimerQueue, hTimer)) {
std::cout << "Entered 2" << std::endl;
if (NULL == (hTimer = Start(hTimerQueue))) return -2;
}
}
std::cin >> input;
}
DeleteTimerQueue(hTimerQueue);
return 0;
}