Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

166
Views
Best way to monitor for a key press without stopping a loop

I'm writing a program in C++ for Linux. I plan on using popen() to run another program. While I'm waiting for that program to finish, I want to be able to detect if the user presses keys on the keyboard so I know if they want to continue processing their files or if they want to pause after pclose(). What is the best way to accomplish this?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

You can use a thread waiting for a key before calling popen, call popen, cancel the thread and check if any key was pressed before calling pclose.

An example using C (it is trivial to adapt it to C++), I'm ommiting error checks for brevity:

#define _XOPEN_SOURCE

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

void *handler(void *arg)
{
    int *key = arg;
    char c;

    while (read(STDIN_FILENO, &c, 1))
    {
        if (*key == 0)
        {
            *key = c;
        }
    }
    return NULL;
}

int main(void)
{
    pthread_t thread;
    int key = 0;

    pthread_create(&thread, NULL, handler, &key);

    // Simulate a long read using sleep 5
    // to give you enough time to press a key + enter
    FILE *cmd = popen("sleep 5; echo 'command finished'", "r");
    char str[1024];

    while (fgets(str, sizeof str, cmd))
    {
        printf("%s", str);
    }
    pthread_cancel(thread);
    pthread_join(thread, NULL);
    if (key != 0)
    {
        printf("%c was pressed\n", key);
    }
    pclose(cmd);
    return 0;
}

EDIT:

Someone suggested in comments to use select instead of pthreads, I don't see much advantage in using select but here we go:

select() allows to wait until a file descriptor (in this case stdin) become ready, it can be connected to a timeout that specifies the interval that select() should block waiting for the file descriptor to become ready, in this case, since we want to read what is pending on stdin as soon as popen finishes, we set the timeout to 0, at the end we need to clean stdin, otherwise we end up poluting the terminal with garbage if the user starts typing but doesn't hit enter, or types more than one digit pressing enter.

IMHO threads are a cleaner alternative in this case. Same approach using select:

#define _XOPEN_SOURCE

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <termios.h>

void clear_stdin(void)
{
    int stdin_copy = dup(STDIN_FILENO);

    tcdrain(stdin_copy);
    tcflush(stdin_copy, TCIFLUSH);
    close(stdin_copy);
}

int keypress(int state)
{
    int key = 0;

    // state 0 = timeout (nothing to get)
    if (state == 1)
    {
        char c;

        if (read(STDIN_FILENO, &c, 1))
        {
            key = c;
        }
    }
    clear_stdin();
    return key;
}

int main(void)
{
    fd_set set;

    FD_ZERO(&set);
    FD_SET(STDIN_FILENO, &set);

    FILE *cmd = popen("sleep 5; echo 'command finished'", "r");
    char str[1024];

    while (fgets(str, sizeof str, cmd))
    {
        printf("%s", str);
    }

    struct timeval timeout;

    timeout.tv_sec = 0;
    timeout.tv_usec = 0;

    int state = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
    int key = keypress(state);

    if (key != 0)
    {
        printf("%c was pressed\n", key);
    }
    pclose(cmd);
    return 0;
}
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!