C++ - Making an event loop

感情迁移 提交于 2019-12-13 06:12:48

问题


Does anyone know how to make an event loop in c++ without a library? It doesn't have to be cross-platform, I'm on a Mac. Basically, I want the program to run and do nothing until the user presses the up arrow key, then the program will output "You pressed up" or something. All i can think of is having an infinite while or for loop and get input with cin, but I don't think cin can detect arrow keys and I believe it pauses the program until it reaches a '\n';

I would want it to look like this:

void RUN()
{
   while(true)
   {
      // poll events and do something if needed
   }
}

int main()
{
   RUN();
}

I'm kinda sure it's possible without threads, and I've heard that this can be accomplished with fd_set or something, but I'm not sure how.

Any help would be really appreciated.

EDIT:

The program has to run in the background when there aren't any events. For example, Microsoft Word doesn't stop until the user presses a button, it keeps running. I want something like that, but command-line not GUI.


回答1:


Since you're talking keyboard input, and not looking for a Mac look and feel, what you want is the UNIX way of doing it. And that is,

1) set the terminal in either raw or cbrk mode (I forget which). 2) now use read() to read single characters at a time. 3) temporarily echo the character read (as an int) so you can find what the up arrow key gives you.

As for the more general event loop question, where the only input device is the keyboard, you sit in a loop, and whenever a key is typed (in raw mode?) you call a routine with the value of the key typed. If you had more input devices, you would need multiple threads each could listen to a different device, putting what they find on a queues (with appropriate locking). The main loop would then check the queue and call a routine appropriately everytime something appears in it.




回答2:


You can use ncurses and enable cbreak to get the raw input stream.




回答3:


I've used a while loop with signal handlers. Like this incomplete snippet.

void getSomething()
{
  std::cout << "Enter new step size: "; std::cout.flush();
  std::cin >> globalVariable;
  std::getchar();  // consume enter key.
}

void printCommands()
{
  std::cout << "1: do something\n"
        << "q: quit\n"
    << "h: help\n"
    << std::endl;
}

void getCommand()
{
  // Output prompt 
  std::cout << "Enter command ('h' for help): "; std::cout.flush();

  // Set terminal to raw mode 
  int ret = system("stty raw"); 

  // Wait for single character 
  char input = std::getchar(); 

  // Reset terminal to normal "cooked" mode 
  ret = system("stty cooked"); 

  std::cout << std::endl;

  if (input == 'h') printCommands();
  else if (input == '1') getSomething();
  else if (input == 'q') {
    g_next = true;
    g_quit = true;
  } 
}

void 
signalHandler(int signo)
{
  if (signo == SIGINT) {
    g_next = true;
  } else if (signo == SIGQUIT) {
    getCommand();
  }
}

int main(int argc, char* argv[])
{
  signal(SIGINT, signalHandler);
  signal(SIGUSR1, signalHandler);
  signal(SIGQUIT, signalHandler);

  do {
    // Stuff
  } while (!g_quit);

  exit(0);
}



回答4:


The question has been updated to say "The program has to run in the background ... but command-line not GUI."

All traditional; *NIX shells that can put a program into the background also disconnect the program's standard input from the terminal, so AFAIK, this has become impossible.


This does not need to be Mac specific. The Mac supports *NIX mechanisms for reading characters from a keyboard.

AFAICT all the program is doing is waiting for a character, so it might as well block.

Normally the terminal device, tty (teletype!), is interpreting characters typed on the keyboard before your program can read them from standard input. Specifically the tty device normally buffers an entire line of text, and intercepts the rubout character (and a few others like CTRL+w) to edit the line of text. This pre-processing of characters is called a 'line discipline'

You need to set the tty device driver to stop doing that! Then you can get all of the characters the user types.

You change the device using ioctl or termios on the file descriptor.

Search for e.g. "ioctl tty line discipline raw" to understand the details, and find program examples.

You can set the terminal to 'raw' using the command line program stty. Please read the stty man page because setting it back can be slightly tricky (NB: if you make a mistake it is often easier to kill the terminal, than try to fix it, because there is not echoing of anything you type)

It is possible that the up-arrow is not a single char, so it will require some byte-at-a-time decoding to avoid blocking at the wrong point in the input stream, i.e. if some input sequences are one character, and others two, or three characters, the decoding needs to happen at each byte to decide if there is a pending byte, or one too many read's might get issued, which would cause the program to block.



来源:https://stackoverflow.com/questions/9930323/c-making-an-event-loop

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!