How to trigger a function when control c is pressed in c++ - c++

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);
}
}
}

Related

Trying to make something write to a file in c++

I tried programming a file writer, but when i try to write to a file with something that has multiple words it will suddenly create files.
My code
#include <fstream>
#include <iostream>
#include <unistd.h>
int main(int argc, char *argv[]) {
char cwd[256];
while (true) {
getcwd(cwd, 256);
std::string cwd_s = (std::string)cwd;
std::string Input;
std::cout << cwd_s << "> ";
std::cin >> Input;
std::ofstream file(Input);
std::cout << "cmd /";
std::cin >> Input;
file << Input;
};
for (int i; i < argc; i++) {
std::cout << argv[i] << '\n';
};
return 0;
}
I expected to get this:
C:\Users\code> File.txt
cmd /hello world!
File.txt
hello world!
But it only had "hello", it created another file named world!
I have tried changing the code, but to no avail.
So I have wrote this code that I think does what you expect. The behavior you were seing is because you used the same string to store the filename and the user input. Also you redefined a new file every loop (without closing the previous one). I added a signal handler since if you press Ctrl+C the program would quit without saving/closing the file.
I added comments about how you can make a better CLI interface (if you're interested)
#include <iostream>
#include <fstream>
#include <string>
#include <unistd.h>
std::ofstream outfile;
void signalHandler(int signum) {
outfile.close();
exit(signum);
}
int main() {
char cwd[256];
if (getcwd(cwd, sizeof(cwd)) != NULL) {
std::cout << cwd << "> ";
} else {
std::cerr << "Error: Could not get current working directory." << std::endl;
return 1;
}
std::string filename;
std::getline(std::cin, filename);
outfile.open(filename);
// We intercept the Ctrl+C signal to close the file before exiting. Else nothing will be written to it.
// You can also use Ctrl+D (EOF: End Of File) to exit the program.
// The best praticte would be to implement a command line interface with a "quit" command. (like a map<string, function> for example)
signal(SIGINT, signalHandler);
// Another good practice is to check if the file did open correctly.
if (!outfile.is_open()) {
std::cerr << "Error: Could not open file for writing." << std::endl;
return 1;
}
std::cout << "cmd / ";
char ch;
while (std::cin.get(ch)) {
outfile.put(ch);
if (ch == '\n') {
std::cout << "cmd / ";
}
}
outfile.close();
return 0;
}
Hope it will help you ! And if you have any question about the code feel free to ask I'll explain !

How to wait for a specific keystroke?

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");
}

Function to interrupt the loop by any pressed key

I'm new to C++. Have decided to do my own game. And i want to make a starting screen for it. And the problem is that i havent found the way to make an "Press any key to continue" function while dots continue. I made the loop for the programm to wait till any would be pressed but dots dont want to display in.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <windows.h>
using namespace std;
int pressCheck(){
char c = 0;
c = getchar();
if (c == 0)
return 1;
return 0;
}
int main()
{
cout << "\t\t\t\t Hello" << endl;
Sleep(300);
cout << "\t\t Welcome to my new game BITHCES!" << endl << endl;
Sleep(700);
cout << "\t\t\tPress any key to proceed";
while(!pressCheck()){
Sleep(300);
cout << ".";
Sleep(300);
cout << ".";
Sleep(300);
cout << ".";
}
getchar();
system("cls");
Sleep(100);
return 0;
}
If you are creating a text based game I would recommend using ncurses (or pdcurses for windows):
[...] a toolkit for developing "GUI-like" application software that runs
under a terminal emulator.
Implementing what you have above would be something like
#include <string>
#include <ncurses.h> // This header might be different on windows
#include <unistd.h> // for usleep, replace with Windows.h (?)
void DisplayCentre(int yy, const std::string& str)
{
// Get the screen size
int y, x;
getmaxyx(stdscr, y, x);
// Compute starting location for string (centre)
x = (x - str.size())/2;
// Write the string to the window
mvwprintw(stdscr, yy, x, str.c_str());
// Make sure the screen is updated
refresh();
}
void PromptForKey(void)
{
// Get the screen size
int y, x;
getmaxyx(stdscr, y, x);
// Write a message at the bottom left of the screen
mvwprintw(stdscr, y-1, 0, "Press any key to continue");
// Set a time-out for wgetch
wtimeout(stdscr, 300);
// While the user hasn't entered a character
while (wgetch(stdscr) == ERR)
{
// Add another dot to the screen
waddch(stdscr, '.');
refresh();
}
// Clear time-out
notimeout(stdscr, true);
}
int main(int argc, char** argv)
{
initscr(); // Initialize curses
cbreak(); // Make typed characters immediately available
noecho(); // Don't automatically print typed characters
curs_set(0); // Make the cursor invisible (where supported)
// Display `Hello' (at line 10)
DisplayCentre(10, "Hello");
// Delay (you might want to use Sleep())
sleep(1);
// Display `Welcome to my new game' (at line 15)
DisplayCentre(15, "Welcome to my new game");
sleep(1);
// Prompt user for key
PromptForKey();
// Close down curses
endwin();
return 0;
}
To compile this program on Linux I use g++ test.cpp -lncurses. On windows you will probaly need to replace sleep with the windows Sleep function and use the appropriate header. You may also need to use an alternative to ncurses.
However, if you are just learning to program I would suggest you try using ncurses in Python. Python has the benefit of being an interpreted language so you don't need to worry too much about compiling or linking executables. Python is also mostly cross platform. The above implemented in Python:
#!/usr/bin/python
from curses import *
from time import sleep
def promptForKey(win):
""" Ask the user to press any key to continue. """
# Get screen size
y,x = win.getmaxyx()
# Display prompt
win.addstr(y-1, 0, "Press any key to continue")
win.refresh()
# Set time-out
win.timeout(300)
while (win.getch() == ERR):
win.addch('.')
# Disable time-out
win.notimeout(True)
def dispCentre(win, yy, string, delay):
""" Display string at line yy and wait for delay milliseconds. """
# Get screen size
y,x = win.getmaxyx()
# Display string in centre
x = (x - len(string))/2
win.addstr(yy, x, string)
win.refresh()
# Delay
sleep(delay)
if __name__ == '__main__':
# Initialize curses
win = initscr()
cbreak()
noecho()
curs_set(0)
# Display some stuff
dispCentre(win, 10, "Hello", 0.3)
dispCentre(win, 15, "Welcome to my new game", 0.7)
promptForKey(win)
# Close down curses
endwin()
i know i am late but i think maybe you wanted to do this? (Run the attached code)
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <windows.h>
#include<conio.h>
using namespace std;
bool pressCheck(){
if (getch())
return 1;
return 0;
}
int main()
{
cout << "\t\t\t\t Hello" << endl;
Sleep(300);
cout << "\t\t Welcome to my new game BITHCES!" << endl << endl;
Sleep(700);
cout << "\t\t\tPress any key to proceed";
while(!pressCheck()){
Sleep(300);
cout << ".";
Sleep(300);
cout << ".";
Sleep(300);
cout << ".";
}
system("cls");
Sleep(100);
return 0;
}

How to show terminal in linux application?

I was wondering if you could have it so when you go and click on a program in linux it always automatically brings up the command line for the information being displayed or if I decided to use ncurses for an interface. If so is this a system specific call or can you do this with ncurses? Because half of my program is going to be via terminal.
Thanks
Since nitt wouldn't let me amend his code snippet, I'm posting a corrected snippet in case anyone would like to use it:
#include <cstdio>
#include <unistd.h>
#include <iostream>
int main(int argc, char* argv[])
{
if (isatty(0))
{
std::cout << "Hello, World!" << std::endl;
for (int i=0; i<argc; i++)
std::cout << "arg: " << i << "\t" << argv[i] << std::endl;
std::cout << "Press return to continue . . ." << std::flush;
std::cin.get();
}
else
{
const char* args[argc+3], **it=args;
*it++ = "gnome-terminal";
*it++ = "-x";
it = std::copy(argv, argv+argc, it);
*it++ = 0;
if (-1 == execvp("gnome-terminal", (char* const*) &args[0]))
perror("exec");
}
}
Yes, just invoke a terminal with your app in it. For example:
rxvt -e myapp
Starts a terminal running your app. You could also use xterm. If you want to use wide chars/unicode I recommend rxvt-unicode.
You can put this in a .desktop file with an icon defined there, and then that will be placed in the system menu.
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int fileExists(string x321) {
ifstream x123 (x321.c_str());
string x213;
x123 >> x213;
if (x213 == "") {
return false;
} else {
return true;
}
}
int createConsole(string fname) {
if (fileExists("~tmp") == false) {
ofstream tmp ("~tmp");
tmp << "tmpfile";
fname = "gnome-terminal -e " + fname;
system(fname.c_str());
system("exit");
return 0;
}
remove("~tmp");
return 1;
}
int main(int argc, char** args) {
createConsole(args[0]);
cout << "Hello, World!" << endl;
cout << "Press return to continue . . .";
cin.get();
}
Pay attention to the "createConsole" and "fileExists" function. I wrote this myself.

Implement "tail -f" in C++

I want to create a small code in C++ with the same functionality as "tail-f": watch for new lines in a text file and show them in the standard output.
The idea is to have a thread that monitors the file
Is there an easy way to do it without opening and closing the file each time?
Have a look at inotify on Linux or kqueue on Mac OS.
Inotify is Linux kernel subsystem that allows you to subscribe for events on files and it will report to your application when the even happened on your file.
Just keep reading the file. If the read fails, do nothing. There's no need to repeatedly open and close it. However, you will find it much more efficient to use operating system specific features to monitor the file, should your OS provide them.
Same as in https://stackoverflow.com/a/7514051/44729 except that the code below uses getline instead of getc and doesn't skip new lines
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;
static int last_position=0;
// read file untill new line
// save position
int find_new_text(ifstream &infile) {
infile.seekg(0,ios::end);
int filesize = infile.tellg();
// check if the new file started
if(filesize < last_position){
last_position=0;
}
// read file from last position untill new line is found
for(int n=last_position;n<filesize;n++) {
infile.seekg( last_position,ios::beg);
char test[256];
infile.getline(test, 256);
last_position = infile.tellg();
cout << "Char: " << test <<"Last position " << last_position<< endl;
// end of file
if(filesize == last_position){
return filesize;
}
}
return 0;
}
int main() {
for(;;) {
std::ifstream infile("filename");
int current_position = find_new_text(infile);
sleep(1);
}
}
I read this in one of Perl manuals, but it is easily translated into standard C, which, in turn, can be translated to istreams.
seek FILEHANDLE,POSITION,WHENCE
Sets FILEHANDLE's position, just like the "fseek" call of
"stdio".
<...>
A WHENCE of 1 ("SEEK_CUR") is useful for not moving the file
position:
seek(TEST,0,1);
This is also useful for applications emulating "tail -f". Once
you hit EOF on your read, and then sleep for a while, you might
have to stick in a seek() to reset things. The "seek" doesn't
change the current position, but it does clear the end-of-file
condition on the handle, so that the next "<FILE>" makes Perl
try again to read something. We hope.
As far as I remember, fseek is called iostream::seekg. So you should basically do the same: seek to the end of the file, then sleep and seek again with ios_base::cur flag to update end-of-file and read some more data.
Instead of sleeping, you may use inotify, as suggested in the other answer, to sleep (block while reading from an emulated file, actually) exactly until the file is updated/closed. But that's Linux-specific, and is not standard C++.
I needed to implement this too, I just wrote a quick hack in standard C++. The hack searches for the last 0x0A (linefeed character) in a file and outputs all data following that linefeed when the last linefeed value becomes a larger value. The code is here:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int find_last_linefeed(ifstream &infile) {
infile.seekg(0,ios::end);
int filesize = infile.tellg();
for(int n=1;n<filesize;n++) {
infile.seekg(filesize-n-1,ios::beg);
char c;
infile.get(c);
if(c == 0x0A) return infile.tellg();
}
}
int main() {
int last_position=-1;
for(;;) {
ifstream infile("testfile");
int position = find_last_linefeed(infile);
if(position > last_position) {
infile.seekg(position,ios::beg);
string in;
infile >> in;
cout << in << endl;
}
last_position=position;
sleep(1);
}
}
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <sys/stat.h>
#include <stdlib.h>
#define debug 0
class MyTail
{
private:
std::list<std::string> mLastNLine;
const int mNoOfLines;
std::ifstream mIn;
public:
explicit MyTail(int pNoOfLines):mNoOfLines(pNoOfLines) {}
const int getNoOfLines() {return mNoOfLines; }
void getLastNLines();
void printLastNLines();
void tailF(const char* filename);
};
void MyTail::getLastNLines()
{
if (debug) std::cout << "In: getLastNLines()" << std::endl;
mIn.seekg(-1,std::ios::end);
int pos=mIn.tellg();
int count = 1;
//Get file pointer to point to bottom up mNoOfLines.
for(int i=0;i<pos;i++)
{
if (mIn.get() == '\n')
if (count++ > mNoOfLines)
break;
mIn.seekg(-2,std::ios::cur);
}
//Start copying bottom mNoOfLines string into list to avoid I/O calls to print lines
std::string line;
while(getline(mIn,line)) {
int data_Size = mLastNLine.size();
if(data_Size >= mNoOfLines) {
mLastNLine.pop_front();
}
mLastNLine.push_back(line);
}
if (debug) std::cout << "Out: getLastNLines()" << std::endl;
}
void MyTail::printLastNLines()
{
for (std::list<std::string>::iterator i = mLastNLine.begin(); i != mLastNLine.end(); ++i)
std::cout << *i << std::endl;
}
void MyTail::tailF(const char* filename)
{
if (debug) std::cout << "In: TailF()" << std::endl;
int date = 0;
while (true) {
struct stat st;
stat (filename, &st);
int newdate = st.st_mtime;
if (newdate != date){
system("#cls||clear");
std::cout << "Print last " << getNoOfLines() << " Lines: \n";
mIn.open(filename);
date = newdate;
getLastNLines();
mIn.close();
printLastNLines();
}
}
if (debug) std::cout << "Out: TailF()" << std::endl;
}
int main(int argc, char **argv)
{
if(argc==1) {
std::cout << "No Extra Command Line Argument Passed Other Than Program Name\n";
return 0;
}
if(argc>=2) {
MyTail t1(10);
t1.tailF(argv[1]);
}
return 0;
}