How can I interrupt a cycle by pressing a key in C ++ in OS X?

I would like to do the following in a command line application in OS X:

while (true) {
    // do some task
    if (user_has_pressed('x')) {
        // break out of the loop and do something different
    }
}

For clarity, I do not want the program to block waiting for user input. I run a numerical simulation that takes many hours, and I want to press a key to print detailed statistics about its progress or interrupt it, change parameters, etc.

There are some similar questions that exist , but the answers are either offered only for Windows getch, or they switch the terminal to a different input mode. I do not want to do this because I need to save the possibility of interrupting with ctrl-c, without ruining the terminal.

I do not want to create a Cocoa application, and I do not need to be cross-platform. I'm just looking for the easiest quick and dirty way to do this in a command line application that will only run on my own machine.

I assume one option is to use ncurses. From a brief reading, this seems like a more difficult option than we would like - but if someone publishes a simple minimal example that will accomplish the above task, which will be really useful.

+4
source share
8 answers

Are you looking for the following behavior?

   #include <pthread.h>
   #include <iostream>

   static volatile bool keep_running = true;

   static void* userInput_thread(void*)
   {
       while(keep_running) {
           if (std::cin.get() == 'q')
           {
               //! desired user input 'q' received
               keep_running = false;
           }
       }
   }

   int main()
   {
      pthread_t tId;
      (void) pthread_create(&tId, 0, userInput_thread, 0);

      while ( keep_running )
      {
         //! this will run until you press 'q'
      }

      (void) pthread_join(tId, NULL);

      return 0;
   }
+2
source

, , , stdin. .

#include <poll.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <iostream>

void disable_canonical(){
    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag &= ~ICANON;
    old.c_lflag &= ~ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &old) < 0)
        perror("tcsetattr ICANON");
}
void enable_canonical(){
    struct termios old = {0};
    if (tcgetattr(0, &old) < 0)
        perror("tcsetattr()");
    old.c_lflag |= ICANON;
    old.c_lflag |= ECHO;
    old.c_cc[VMIN] = 1;
    old.c_cc[VTIME] = 0;
    if (tcsetattr(0, TCSANOW, &old) < 0)
        perror("tcsetattr ICANON");
}
bool key_pressed(char c){
    struct pollfd fds[1];
    fds[0].fd = 0;
    fds[0].events = POLLIN;
    fds[0].revents = 0;
    int r = poll(fds, 1, 1);
    if(r > 0){
        if(fds[0].revents & POLLIN || fds[0].revents & POLLRDBAND || fds[0].revents & POLLRDNORM){
            char buffer[1024];
            memset(buffer, 0, sizeof(buffer));
            int n = read(0, buffer, sizeof(buffer) -1);
            for(int i = 0; i < n; ++i){
                if(buffer[i] == c){
                    return true;
                }
            }
        }
    }
    return false;
}

int main(){
    disable_canonical();
    while(true){
        if(key_pressed('x')){
            break;
        }
        usleep(500);
        //std::cout << "looping...\n";
    }
    enable_canonical();
}

P.S. tcsetattr fooobar.com/questions/46788/...

+1

, , , .

goto ++. :

while(true)
{
   char pressKeyToQuit = 'q';
   cin >> pressKeyToQuit;

   if(pressKeyToQuit == 'q')
   {
       goto getOffTheLoop; //to do something different
   }

   getOffTheLoop:
 //do something different
  cout << "Processing!\n";

}

, !: D

+1

:

#include <iostream>
using namespace std;

int main() {
    while (cin.get() != 'x') {
        cout << "I am running." << endl;
    }
    return 0;
}

, , , .

0

POSIX:

#include <signal.h>

static volatile bool keep_continue = true;

int main()
{
    signal(SIGINT, [](int) { keep_continue = false; });

    while (keep_continue)
    {
        // run until you press ctrl-c
    }
}
0

(, ) , ...

#include <fstream>
#include <iostream>
#include <unistd.h>
int main()
{
    while( 1 )
    {

        std::cout << "start" << std::endl;

        std::ifstream ifs( "stop" );

        if( ifs.good() )
        {
            std::cout << "exit" << std::endl;
            ifs.close();
            break;
        }
        ifs.close();
        ifs.open( "pause" );
        while( ifs.good() )
        {
            usleep( 100 );
            ifs.close();
            ifs.open( "pause" );
        }

        std::cout << "end" << std::endl;
    }
}

, , pause ,

touch pause

> pause ( mac os)

,

rm pause

,

> stop ( rm stop )

, ,

alias p='touch ..path_to_executable../pause'

alias s='touch ..path_to_executable../stop'

alias run='if [ -f "..path_to_executable../pause"] ; then rm "..path_to_executable../pause" fi;if [ -f "..path_to_executable../stop"] ; then rm "..path_to_executable../stop" fi; ..path_to_executable../..executable..'

0

?

#include <unistd.h>
#include <fcntl.h>

int main()
{
    int flags = fcntl(0, F_GETFL, 0); // we get the current flags applying on input file descriptor
    fcntl(0, F_SETFL, flags | O_NONBLOCK); // add the non-blocking flag to input file descriptor

    while (read(0, NULL, 0u) < 0)
    {
        // run until you press ENTER key
    }
}

The program will exit when you click ENTER. It works on Debian 9, but I do not have OS X within easy reach to check on it.

0
source

I think you should see an article about - http://cc.byexamples.com/2007/04/08/non-blocking-user-input-in-loop-without-ncurses/

I would comment on this, but I do not have enough reputation.

0
source

Source: https://habr.com/ru/post/1662487/


All Articles