How to make virtual input hardware input? - c++

I wanted to make a strafe bot for garry's mod, and I came up with this:
#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include "stdafx.h"
class KeyBot
{
private:
INPUT _buffer[1];
public:
KeyBot();
void KeyUp(char key);
void KeyDown(char key);
void KeyClick(char key);
};
KeyBot::KeyBot()
{
_buffer->type = INPUT_KEYBOARD;
_buffer->ki.wScan = 0;
_buffer->ki.time = 0;
_buffer->ki.dwExtraInfo = 0;
}
void KeyBot::KeyUp(char key)
{
_buffer->ki.wVk = key;
_buffer->ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, _buffer, sizeof(INPUT));
}
void KeyBot::KeyDown(char key)
{
_buffer->ki.wVk = key;
_buffer->ki.dwFlags = 0;
SendInput(1, _buffer, sizeof(INPUT));
}
void KeyBot::KeyClick(char key)
{
KeyDown(key);
Sleep(10);
KeyUp(key);
}
char check_mouse(POINT xOne, POINT xTwo)
{
GetCursorPos(&xOne);
Sleep(1);
GetCursorPos(&xTwo);
if ((xTwo.x - xOne.x) > 0) {
return 'D';
}
else {
if ((xTwo.x - xOne.x) < 0) {
return 'A';
}
else {
if ((xTwo.x - xOne.x) == 0) {
return 'N';
}
}
}
}
int main()
{
KeyBot bot;
POINT xOne;
POINT xTwo;
while (1) {
if (check_mouse(xOne, xTwo) == 'A') {
bot.KeyUp(0x44);
bot.KeyDown(0x41);
}
if (check_mouse(xOne, xTwo) == 'D') {
bot.KeyUp(0x41);
bot.KeyDown(0x44);
}
if (check_mouse(xOne, xTwo) == 'N') {
bot.KeyUp(0x44);
bot.KeyUp(0x41);
}
}
return 0;
}
This works fine, when opening notepad or game chat, it holds a when I move my mouse left, and it holds d when I move my mouse to the right. The problem is, that, when I am in game, it doesn't move my character at all. I think the problem is that this is a virtual key press and not a hardware one, and I don't know how to change this.
can someone modify my code in order for this to work?

Related

How to pause my console on the desired key

I want to pause my program on the 0x32, 0x33 and 0x34 key and make it work again on the 0x31 key, how can I? I used this code to pause on the 0x32 key, it's working, but I can't get it back to work on the desired key
To summarize what #user4581301 suggested:
#include <conio.h>
...
if (GetAsyncKeyState(0x32) || GetAsyncKeyState(0x33) || GetAsyncKeyState(0x34)) {
while (_getch() != 0x31)
;
}
If your application is a console application, I implemented the function you want through loop. If it's a desktop application, you can refer to my code logic.
#include <iostream>
#include<cstdlib>
#include<time.h>
#include<Windows.h>
#include<conio.h>
using namespace std;
int main()
{
while (true) {
for (int i = 0; i < 5; ++i) {
if (GetAsyncKeyState(gun_keys[i]) && (gun != guns[i])) {
gun = guns[i];
system("cls");
gun_delay = GetTime(gun->rpm);
gun_index = 0;
break;
}
}
if (GetAsyncKeyState(VK_DELETE)) //Bind key, what close this program
{
ExitProcess(-1); //Exit Process
}
if (GetAsyncKeyState(MOUSEEVENTF_MOVE) < 0) {
if (!is_mouse_down) {
is_mouse_down = true;
if (gun != nullptr)
gun_index = 0;
}
if (gun != nullptr && gun_index != gun->len) {
mouse_event(MOUSEEVENTF_MOVE, long(gun->pattner[gun_index][0] * K), long(gun->pattner[gun_index][1] * K), 0, 0);
++gun_index;
Sleep(gun_delay);
continue;
}
}
else
is_mouse_down = false;
if (_kbhit())//Checks if there is currently keyboard input and returns a non-zero value if there is, or 0 otherwise
{
int ch = _getch();
if (ch == 0x32 || ch == 0x33 || ch == 0x34)
{
ch = _getch();//It waits for input and pauses the program
}
if (ch != 0x31)
{
while (true)
{
if (_kbhit())
{
int ch = _getch();
if (ch == 0x31) break;
}
}
}
fflush(stdin);//Clear the input buffer
}
Sleep(150);
}
return 0;
}

how do i call a function in loop from another function in void loop arduino

#define CLK 2
#define DT 3
#define SW 4
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27);
int counter = 0;
int currentStateCLK;
int lastStateCLK;
int lastCLK,cnt=0,btnState,lastPress=0;
String currentDir ="";
unsigned long lastButtonPress = 0;
char *mainmenu[] ={"SET MODE","SET TEMP","SET HUMD","SERVO","RESET"};
char *setmode[] ={"INCUBATOR","HATCHER","BACK"};
void setup() {
// Set encoder pins as inputs
Wire.begin();
Wire.beginTransmission(0x27);
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);
lcd.begin(16, 2);
lcd.setBacklight(255);
lcd.home(); lcd.clear();
Serial.begin(9600);
lastStateCLK = digitalRead(CLK);
delay(100);
if(EEPROM_READ(0)==NULL){
SET_MODE();
}
Serial.print(EEPROM_READ(0));
}
void loop(){
disp();
rot();
}
void disp(){
lcd.setCursor(0,0);
lcd.print(" KGF");
}
void rot() {
int lim=sizeof(mainmenu)/2;
Serial.print(lim);
currentStateCLK = digitalRead(CLK);
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
lcd.clear();
lcd.setCursor(0, 1);
if (digitalRead(DT) != currentStateCLK) {
counter --;
if(counter<0){
counter=lim-1;
}
}
else {
// Encoder is rotating CW so increment
counter ++;
if(counter>lim-1){
counter=0;
}
lcd.print(mainmenu[counter]);
}
lastStateCLK = currentStateCLK;
int btnState = digitalRead(SW);
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
if(counter==0){
SET_MODE();
}
}
}
lastButtonPress = millis();
}
delay(1);
}
void SET_MODE(){
int lim=sizeof(setmode)/2;
int currentCLK = digitalRead(CLK);
if (currentCLK != lastCLK && currentCLK == 1){
lcd.clear();
lcd.setCursor(0, 1);
if (digitalRead(DT) != currentCLK) {
cnt --;
if(cnt<0){
cnt=lim-1;
}
}
else {
// Encoder is rotating CW so increment
cnt ++;
if(cnt>lim-1){
cnt=0;
}
}
lcd.print(setmode[cnt]);
}
lastCLK = currentCLK;
btnState = digitalRead(SW);
if (btnState == LOW) {
//if 50ms have passed since last LOW pulse, it means that the
//button has been pressed, released and pressed again
if (millis() - lastButtonPress > 50) {
if(setmode[cnt]=="BACK"){
exit(0);
}
lcd.clear();
lcd.setCursor(0, 1);
EEPROM_WRITE(0,setmode[cnt]);
lcd.print("DONE");
}
lastPress = millis();
}
delay(1);
}
void EEPROM_WRITE(int addrOffset, const String &strToWrite)
{
byte len = strToWrite.length();
EEPROM.write(addrOffset, len);
for (int i = 0; i < len; i++)
{
EEPROM.write(addrOffset + 1 + i, strToWrite[i]);
}
}
String EEPROM_READ(int addrOffset)
{
int newStrLen = EEPROM.read(addrOffset);
char data[newStrLen + 1];
for (int i = 0; i < newStrLen; i++)
{
data[i] = EEPROM.read(addrOffset + 1 + i);
}
data[newStrLen] = '\0';
return String(data);
}
I want to call the SET_MODE() function in the loop from rot() function, I am building a menu based program so the SET MODE menu should redirect to the SET_MODE() function, and as I will be adding more menu and sub-menus how can I perform this task.
The SET_MODE() function doesn't work in loop I do not know why, it only works when I all it under void loop() directly.

Keypress Simulation in Games [C++]

So I have a working keypress simulator. It presses the key "W" every 2 seconds. I'm testing it out on a game that uses the keys 'WASD' however, when I run the program and run up my game, it doesn't move my character? I have to physically push the W key to move it. Any ideas why?
Here's my code:
#include <iostream>
#define WINVER 0x0500
#include <windows.h>
class KeyBot {
private:
INPUT _buffer[1];
public:
KeyBot();
void KeyUp(char key);
void KeyDown(char key);
void KeyClick(char key);
};
KeyBot::KeyBot() {
_buffer->type = INPUT_KEYBOARD;
_buffer->ki.wScan = 0;
_buffer->ki.time = 0;
_buffer->ki.dwExtraInfo = 0;
}
void KeyBot::KeyUp(char key) {
_buffer->ki.wVk = key;
_buffer->ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, _buffer, sizeof(INPUT));
}
void KeyBot::KeyDown(char key) {
_buffer->ki.wVk = key;
_buffer->ki.dwFlags = 0;
SendInput(1, _buffer, sizeof(INPUT));
}
void KeyBot::KeyClick(char key) {
KeyDown(key);
Sleep(10);
KeyUp(key);
}
int main() {
KeyBot bot;
while (1) {
bot.KeyDown(0x57); //Press and hold 'W'
Sleep(2000); // Wait 2000 ms (2 seconds)
bot.KeyUp(0x37);
}
}
This thread describes a similar problem - DirectX input handling seem to ignore normal scancodes; try using their DIK_ variant, from the dinput.h DirectX header.

Mix_LoadWAV returns NULL when it shouldn't

I'm making a game in C++, but I've been running into an issue I just can't figure out when it comes to the sound. I'm using SDL_Mixer, with Mix_Music for the music and Mix_Chunk for the sound effects, but for some reason when I try to load a sound effect file using MIX_LoadWAV it returns NULL.
The thing is, when I load the same file using MIX_LoadMUS (loading as music instead of sound effect), it loads fine.
I can't find any differences that would explain the issue; the only difference is Mix_LoadWAV instead of Mix_LoadMUS, but why? Mix_LoadMUS doesn't work for Mix_Chunk, or else I'd just use that, but ...
Here, I'll show you the code for the sound manager I use. MusicClip being a Mix_Music and SoundClip being a Mix_Chunk.
#include "stdafx.h"
#include "SoundManager.h"
#include "MusicClip.h"
#include "SoundClip.h"
SoundManager::SoundManager()
{
}
SoundManager::~SoundManager()
{
Shutdown();
}
bool SoundManager::Initialize()
{
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
}
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0)
{
printf(" SDL_mixer :: Msx_OpenAudio %s\n", Mix_GetError());
return false;
}
return true;
}
void SoundManager::Shutdown()
{
for (unsigned int i = 0; i < m_axSoundClips.size(); i++)
{
delete m_axSoundClips[i];
m_axSoundClips[i] = nullptr;
}
m_axSoundClips.clear();
for (unsigned int i = 0; i < m_axMusicClips.size(); i++)
{
delete m_axMusicClips[i];
m_axMusicClips[i] = nullptr;
}
m_axMusicClips.clear();
{
std::map<std::string, Mix_Chunk*>::iterator it = m_axSounds.begin();
while (it != m_axSounds.end())
{
Mix_FreeChunk(it->second);
it->second = nullptr;
it++;
}
m_axSounds.clear();
}
{
std::map<std::string, Mix_Music*>::iterator it = m_axMusic.begin();
while (it != m_axMusic.end())
{
Mix_FreeMusic(it->second);
it->second = nullptr;
it++;
}
m_axMusic.clear();
}
Mix_CloseAudio();
}
MusicClip *SoundManager::CreateMusicClip(std::string p_sFilename)
{
MusicClip *Ret = nullptr;
std::map<std::string, Mix_Music*>::iterator it = m_axMusic.find(p_sFilename);
if (it == m_axMusic.end())
{
Mix_Music* Music = Mix_LoadMUS(p_sFilename.c_str());
if (Music == NULL) {
printf("Error; music will not play\n");
printf(p_sFilename.c_str());
printf("\n");
printf(Mix_GetError());
}
std::pair<std::string, Mix_Music*> Pair;
Pair = std::make_pair(p_sFilename, Music);
Ret = new MusicClip(Music);
}
else
Ret = new MusicClip(it->second);
m_axMusicClips.push_back(Ret);
return Ret;
}
SoundClip *SoundManager::CreateSoundClip(std::string p_sFilename)
{
SoundClip *Ret = nullptr;
std::map<std::string, Mix_Chunk*>::iterator it = m_axSounds.find(p_sFilename);
if (it == m_axSounds.end())
{
Mix_Chunk* Sound = Mix_LoadWAV(p_sFilename.c_str());
if (Sound == NULL) {
printf("\nError; sound will not play\n");
printf(p_sFilename.c_str());
printf("\n");
printf(Mix_GetError());
}
std::pair<std::string, Mix_Chunk*> Pair;
Pair = std::make_pair(p_sFilename, Sound);
Ret = new SoundClip(Sound);
}
else
Ret = new SoundClip(it->second);
m_axSoundClips.push_back(Ret);
return Ret;
}
Here's the code for MusicClip and SoundClip; They seem identical aside from me adding PlayOnce and fadeout to MusicClip.
#include "stdafx.h"
#include "SoundClip.h"
SoundClip::SoundClip()
{
m_pxClip = nullptr;
m_iChannel = -1;
}
SoundClip::~SoundClip()
{
m_pxClip = nullptr;
}
SoundClip::SoundClip(Mix_Chunk* p_pxClip)
{
m_pxClip = p_pxClip;
m_iChannel = -1;
}
void SoundClip::Play()
{
m_iChannel = Mix_PlayChannel(-1, m_pxClip, 0);
}
void SoundClip::Stop()
{
if (m_iChannel == -1)
return;
Mix_HaltChannel(m_iChannel);
m_iChannel = -1;
}
void SoundClip::Volume(int p_iVolume)
{
if (m_iChannel == -1)
return;
Mix_Volume(m_iChannel, p_iVolume);
}
void SoundClip::Pause()
{
if (m_iChannel == -1)
return;
if (Mix_Paused(m_iChannel))
{
Mix_Resume(m_iChannel);
}
else
{
Mix_Pause(m_iChannel);
}
}
-
// MusicClip.cpp
#include "stdafx.h"
#include "MusicClip.h"
MusicClip::MusicClip()
{
m_xClip = nullptr;
m_iChannel = -1;
}
MusicClip::~MusicClip()
{
m_xClip = nullptr;
m_iChannel = -1;
}
MusicClip::MusicClip(Mix_Music* p_xClip)
{
m_xClip = p_xClip;
m_iChannel = -1;
}
void MusicClip::Play()
{
m_iChannel = Mix_PlayMusic(m_xClip, -1);
}
void MusicClip::PlayOnce()
{
m_iChannel = Mix_PlayMusic(m_xClip, 1);
}
void MusicClip::Pause()
{
if (m_iChannel == -1)
return;
if ( Mix_PausedMusic() )
Mix_ResumeMusic();
else
Mix_Pause(m_iChannel);
}
void MusicClip::Volume(int p_iVolume)
{
Mix_VolumeMusic(p_iVolume);
oldVolume = p_iVolume;
}
void MusicClip::FadeOut()
{
if (oldVolume>0)
oldVolume--;
Mix_VolumeMusic(oldVolume);
}
void MusicClip::Stop()
{
if (m_iChannel == -1)
return;
Mix_HaltChannel(m_iChannel);
m_iChannel = -1;
}
And this is the code I use to call on the functions. (The soundManager was initialized earlier in the program to start up the BGM.) So this, using the Mix_Chunk* SFX2, won't work:
void GameState::playSFX(std::string FX)
{
SFX2 = soundManager.CreateSoundClip("../assets/sfx/sfx-bleep.wav");
SFX2->Volume(60);
SFX2->Play();
}
But for some reason, if I change SFX2 to a Mix_Music*, this DOES work.
void GameState::playSFX(std::string FX)
{
SFX2 = soundManager.CreateMusicClip("../assets/sfx/sfx-bleep.wav");
SFX2->Volume(60);
SFX2->Play();
}
What do I do? Mix_GetError() doesn't return anything either... If I write the path wrong it returns "couldn't open file", so clearly it can find/open the file, it just... won't? I can't just use Mix_Music for my sound effects either, because if I do they cancel out the music.
By the way, I don't know if it's related, but Mix_LoadMUS won't load non-wav files even though it's supposed to support .ogg and .mp3 too?

prevent write on console at keypress linux c++

I'm trying to do a simple game (Pong) in C++. The game is a "Console-Game".
I've just write part of the code but now I found a trouble:
I create a _getch() and _kbhit() function
int _getch( ) {
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
but when I press a key, that is printed on console. How I can prevent this?
My full code:
#include <iostream>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <stropts.h>
#include <sys/ioctl.h>
using namespace std;
void gotoxy(int x,int y){
printf("\x1b[%d;%df",y,x);
}
int _getch( ) {
struct termios oldt, newt;
int ch;
tcgetattr( STDIN_FILENO, &oldt );
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newt );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
return ch;
}
int _kbhit() {
static const int STDIN = 0;
static bool initialized = false;
if (! initialized) {
// Use termios to turn off line buffering
termios term;
tcgetattr(STDIN, &term);
term.c_lflag &= ~ICANON;
tcsetattr(STDIN, TCSANOW, &term);
setbuf(stdin, NULL);
initialized = true;
}
int bytesWaiting;
ioctl(STDIN, FIONREAD, &bytesWaiting);
return bytesWaiting;
}
class Ball{
public:
};
class Game{
public:
void __init(){
this->pointL = 0;
this->pointR = 0;
}
void addScore(char side){
if(side == 'l') pointL++;
else if(side == 'r') pointR++;
else cout<< "ERROR-2";
return;
}
unsigned int getScore(char side){
if(side == 'l') return this->pointL;
else if (side == 'r') return this->pointR;
else return 0;
}
bool isPlaying(){
return this->playing;
}
bool stop(){
this->playing = false;
return true;
}
private:
unsigned int pointL, pointR;
bool playing;
};
class Player{
public:
int pos[5][2];
int maxX, maxY;
void __init(int maxX, int maxY, char side){
//create matrix with all cords of block of wall (r and l)
this->maxX = maxX;
this->maxY = maxY;
if(side == 'l')
for(int i = 0; i<5; i++){
pos[i][0] = 2;
pos[i][1] = 2+i;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|";
}
else if(side == 'r')
for(int i = 0; i<5; i++){
pos[i][0] = maxX-4;
pos[i][1] = 2+i;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|";
}
else
cout<<"ERRORE-1";
}
void moveUp(){
gotoxy(pos[4][0],pos[4][1]);
cout<< " ";
for(int i = 0; i<5; i++){
pos[i][1] = (pos[i][1] == 0)?pos[i][1]:pos[i][1]-1;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|"; //solid rectangle
}
}
void moveDown(){
gotoxy(pos[4][0],pos[4][1]);
cout<< " ";
for(int i = 0; i<5; i++){
pos[i][1] = (pos[i][1] == this->maxY)?pos[i][1]:pos[i][1]+1;
gotoxy(pos[i][0],pos[i][1]);
cout<< "|"; //solid rectangle
}
}
};
int main(){
int a;
Game game;
Player pl1,pl2;
cout<< "Ridimensiona la finestra come meglio preferisci, quando hai fatto, premi un tasto per continuare";
_getch();
struct winsize size;
ioctl( 0, TIOCSWINSZ, (char *) &size );
printf("\e[2J\e[H");
pl1.__init(size.ws_row, size.ws_col, 'l');
pl2.__init(size.ws_row, size.ws_col, 'r');
//asap menu here
cout<< "TEST: " << size.ws_row;
char key;
while(game.isPlaying()){
if(_kbhit()){
key = _getch();
switch(key){ //when i press that keys, it's printed on terminal, how prevent?
case 'w':
pl1.moveUp();
break;
case 's':
pl2.moveDown();
break;
case 'q':
game.stop();
break;
}
}
}
return 0;
}
Here is a program which does not echo keystrokes but writes the characters to stderr instead. If you compile it, say, with g++ -o t t.cpp then you can start it with e.g. ./t 2>somefile, thus redirecting stderr to somefile.
In a second terminal you can do cat somefile after each keystroke in order to control what the program writes. (Warning: less somefile didn't work on my cygwin installation because the file growth appeared only in chunks in less (I told it to wait for input by pressing "F")).
Since all key strokes are forwarded to the controlling program Control-C or other means to send a signal to the running program via its controlling terminal doesn't work. You have to kill it from a different terminal.
The basic idea is that read() blocks in raw mode until input is available, so there is no need for a separate kbhit().
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
using namespace std;
int main()
{
struct termios oldt;
if( tcgetattr( 0, &oldt ) )
{
fprintf(stderr, "Error getting term attribs\n");
}
cfmakeraw(&oldt);
if( tcsetattr(0, TCSANOW, &oldt) )
{
fprintf(stderr, "Error setting term attribs\n");
}
char inp;
while(true)
{
int bytesRead = read(0, &inp, 1);
if( bytesRead <= 0)
{
fprintf(stderr, "oops, bytes read return val is %d\n", bytesRead);
}
else
{
write(2, &inp, 1);
}
}
}
You may use:
#include <iostream>
#include <stdexcept>
#include <termios.h>
#include <unistd.h>
// A class for mofdifying the behavour of a terminal.
class Terminal
{
// Types
// =====
public:
typedef speed_t speed_type;
// Terminal
// ========
public:
// Initialize the terminal file descriptor and store the attributes of the terminal.
Terminal(int fd)
: m_fd(fd), m_restore(get(fd))
{}
// Restore the orignal attributes of the terminal
~Terminal() {
set(m_fd, m_restore, false);
}
Terminal(const Terminal&) = delete;
const Terminal& operator = (const Terminal&) = delete;
int fd() const { return m_fd; }
void restore() { set(m_fd, m_restore); }
protected:
// Get attributes of a terminal
static termios get(const int fd) {
termios attributes;
if(tcgetattr(fd, &attributes) < 0) {
throw std::runtime_error("Terminal");
}
return attributes;
}
// Set attributes of a terminal
static void set(const int fd, const termios& attributes, bool exception = true) {
if(tcsetattr(fd, TCSANOW, &attributes) < 0 && exception) {
throw std::runtime_error("Terminal");
}
}
// Set attributes of a terminal
static void set(const int fd, int action, const termios& attributes, bool exception = true) {
if(tcsetattr(fd, action, &attributes) < 0 && exception) {
throw std::runtime_error("Terminal");
}
}
private:
int m_fd;
termios m_restore;
};
// A class for mofdifying the input behavour of a terminal.
class StdInputTerminal : public Terminal
{
// Constants
// =========
public:
enum Attributes {
Blocking = 0x01,
Echo = 0x02
};
// Static
// ======
public:
// Clear available input in std::cin
static void clear() {
termios attributes = disable_attributes(Blocking);
while(std::cin)
std::cin.get();
std::cin.clear();
set(fileno(stdin), attributes);
}
// StdInputTerminal
// ================
public:
// Initialize with 'stdin'
StdInputTerminal()
: Terminal(fileno(stdin))
{}
public:
// Disable attributes specified by any combination of Attributes flags
void disable(unsigned flags) { disable_attributes(flags); }
// Disable blocking
void disable_blocking() { disable_attributes(Blocking); }
protected:
// Set attributes of the terminal
static termios disable_attributes(unsigned flags) {
const int fd = fileno(stdin);
termios attributes = get(fd);
termios a = attributes;
if(flags & Blocking) {
a.c_lflag &= ~ICANON;
a.c_cc[VMIN] = 0;
a.c_cc[VTIME] = 0;
}
if(flags & Echo) {
a.c_lflag &= ~ECHO;
}
set(fd, a);
return attributes;
}
};
// Sample Usage
// ============
int kbhit() {
StdInputTerminal terminal;
terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
int result = 0;
char c;
if( ! std::cin.get(c))
std::cin.clear();
else
{
result = c;
std::cin.unget();
}
return result;
}
int getch() {
StdInputTerminal terminal;
terminal.disable(StdInputTerminal::Blocking | StdInputTerminal::Echo);
char result = 0;
while(true) {
std::cin.get(result);
if(std::cin.eof()) {
std::cin.clear();
usleep(100000);
}
else break;
}
if(std::cin.fail()) {
std::cin.clear();
result = 0;
}
return result;
}
// Test
// ====
int main()
{
std::cout << "Enter a single sample character: ";
char c;
std::cin.get(c);
std::cin.unget();
if(kbhit()) {
int ch = getch();
std::cout << "Entered character: " << char(ch);
if(kbhit()) {
int ch = getch();
std::cout << " Newline " << char(ch);
if(kbhit()) {
std::string line;
getline(std::cin, line);
std::cout << "\nToo many sample characters: " << line << '\n';
}
}
}
}
(Please excuse the incomplete classes, thy are experimental)