+static void handle_command(int c)
+{
+ int i;
+
+ /* first check user-defined key bindings */
+ for (i = 0; i < conf.key_map_given; ++i) {
+ char *tmp, *handler, *arg;
+
+ tmp = para_strdup(conf.key_map_arg[i]);
+ if (!split_key_map(tmp, &handler, &arg)) {
+ free(tmp);
+ return;
+ }
+ if (strcmp(tmp, km_keyname(c))) {
+ free(tmp);
+ continue;
+ }
+ if (*handler == 'd')
+ display_cmd(arg);
+ else if (*handler == 'x')
+ external_cmd(arg);
+ else if (*handler == 'p')
+ para_cmd(arg);
+ else if (*handler == 'i') {
+ int num = find_cmd_byname(arg);
+ if (num >= 0)
+ command_list[num].handler();
+ }
+ free(tmp);
+ return;
+ }
+ /* not found, check internal key bindings */
+ for (i = 0; command_list[i].handler; i++) {
+ if (!strcmp(km_keyname(c), command_list[i].key)) {
+ command_list[i].handler();
+ return;
+ }
+ }
+ print_in_bar(COLOR_ERRMSG, "key '%s' is not bound, press ? for help",
+ km_keyname(c));
+}
+
+static void input_pre_select(int mode, fd_set *rfds, int *max_fileno)
+{
+ if (mode == GETCH_MODE || mode == COMMAND_MODE)
+ para_fd_set(STDIN_FILENO, rfds, max_fileno);
+}
+
+static int input_post_select(int mode)
+{
+ int ret;
+
+ switch (mode) {
+ case COMMAND_MODE:
+ ret = wgetch(top.win);
+ if (ret != ERR && ret != KEY_RESIZE) {
+ if (cmd_pid)
+ kill(cmd_pid, SIGTERM);
+ return -1;
+ }
+ return 0;
+ case GETCH_MODE:
+ ret = wgetch(top.win);
+ if (ret != ERR && ret != KEY_RESIZE)
+ return ret;
+ return 0;
+ case EXTERNAL_MODE:
+ if (cmd_pid == 0)
+ return -1;
+ return 0;
+ default:
+ assert(false); /* bug */
+ }
+}
+
+static void signal_pre_select(fd_set *rfds, int *max_fileno)
+{
+ para_fd_set(signal_pipe, rfds, max_fileno);
+}
+
+/*
+ * This is the core select loop. Besides the (internal) signal
+ * pipe, the following other fds are checked according to the mode:
+ *
+ * GETCH_MODE: check stdin, return when key is pressed
+ *
+ * COMMAND_MODE: check command fds and stdin. Return when peer has closed both
+ * stdout and stderr or when any key is pressed.
+ *
+ * EXTERNAL_MODE: Check only signal pipe. Used when an external command
+ * is running. During that time curses is disabled. Returns when
+ * cmd_pid == 0.
+ */
+static int do_select(int mode)
+{
+ fd_set rfds;
+ int ret, max_fileno;
+ struct timeval tv;
+
+repeat:
+ tv.tv_sec = conf.timeout_arg / 1000;
+ tv.tv_usec = (conf.timeout_arg % 1000) * 1000;
+// ret = refresh_status();
+ FD_ZERO(&rfds);
+ max_fileno = 0;
+ status_pre_select(&rfds, &max_fileno, &tv);
+ signal_pre_select(&rfds, &max_fileno);
+ command_pre_select(mode, &rfds, &max_fileno);
+ input_pre_select(mode, &rfds, &max_fileno);
+ ret = para_select(max_fileno + 1, &rfds, NULL, &tv);
+ if (ret <= 0)
+ goto check_return; /* skip fd checks */
+ signal_post_select(&rfds);
+ /* read command pipe if ready */
+ ret = command_post_select(mode, &rfds);
+ if (ret < 0)
+ return 0;
+ status_post_select(&rfds);
+check_return:
+ ret = input_post_select(mode);
+ if (ret != 0)
+ return ret;
+ goto repeat;
+}
+