ncurses не фиксирует движения мыши, но терминал

Я могу echo -e "\e[?1003h" и наблюдать, как мой терминал поглощает события движения мыши, как конфеты, но проклятиям они, похоже, совсем не нужны. я посмотрел на

События движения мыши в NCurses

но похоже, что эта проблема была решена путем изменения env TERM, что мне не поможет, потому что мой терминал действительно реагирует на события перемещения мыши, однако ncurses нет. Вот что я пробовал (этот код почти полностью взят из другого вопроса):

#include <ncurses.h>
#include <assert.h>

int main(){
        int ch, count=0;
        mmask_t old;

        initscr ();
        noecho ();
        cbreak ();
        mousemask (ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, &old);
        keypad (stdscr, TRUE);
        printf("\033[?1003h");

        while ((ch = getch ()) != 'q')
        {
          count++;
          if (ch == KEY_MOUSE)
          {
             MEVENT event;
             assert (getmouse (&event) == OK);
             mvprintw (0, 0, "Mouse Event!\n");
          }
          mvprintw (1, 1, "Event number %4d",count);
          refresh();
        }
        endwin();

}

Дополнительная информация и предупреждение:

Эта программа на самом деле способна обнаруживать движение мыши ПОСЛЕ выполнения. Это можно отменить командой echo -e "\e[?1000h"


person AlgoRythm    schedule 04.12.2018    source источник
comment
По умолчанию printf() буферизуется строкой: библиотека C кэширует данные внутри, пока не появится новая строка. Чтобы исправить, используйте printf("\033[?1003h"); fflush(stdout);. Точно так же добавьте printf("\033[?1000h"); fflush(stdout); перед endwin();, чтобы восстановить поведение по умолчанию при выходе из программы.   -  person Nominal Animal    schedule 04.12.2018
comment
@NominalAnimal Пожалуйста, напишите это как ответ, и я приму его. Я не смог найти это нигде во время моих исследований, большое спасибо :)   -  person AlgoRythm    schedule 04.12.2018


Ответы (1)


В то время как printf и curses записывают в стандартный вывод, ncurses не будет сбрасывать stdout, так как выполняет собственную буферизацию. Как указано в примечаниях к выпуску ncurses 6.0 (август 2015 г.):

Буферизация вывода представляла собой еще одно, но полезное отвлечение. Отчет об ошибке 2012 года, касающийся использования обработчиков сигналов в ncurses, указал на проблему с использованием небезопасных функций для обработки SIGTSTP. Другие сигналы можно устранить с помощью обходных путей; ремонт SIGTSTP требовал другого подхода. Решение требовало изменения внутреннего поведения библиотеки: того, как она обрабатывает буферизацию вывода.

Теперь ncurses буферизует собственный вывод независимо от стандартного вывода. Несколько приложений полагались на прямое повторное использование библиотекой стандартной буферизации вывода; однако это неуказанное поведение и никогда не было рекомендуемой практикой. Идентификация этих приложений, а также уточнение изменений, позволяющих низкоуровневым приложениям работать согласованно, потребовали времени.

Хотя пример может сработать, если за вызовом printf следует fflush(stdout), нет гарантии, что он будет работать бесконечно, поскольку ncurses не нужно отправлять свои mouse-initialization до вызова getch. Рекомендуемый способ работы с ncurses — помещать эту информацию в описание терминала, позволяя ncurses решать, когда вносить изменения в экран.

В базе данных терминала ncurses уже есть пример: xterm-1003

person Thomas Dickey    schedule 04.12.2018
comment
Полностью согласен. Именно из-за этого наличие printf() и fflush(stdout) перед вызовом mousemask() обычно не работает (поскольку mousemask() переопределяет режим в соответствии с конфигурацией терминала). Конечно, запуск примера как TERM=xterm-1003 ./example будет работать во многих эмуляторах терминала (по крайней мере, gnome-terminal, xterm, mate-terminal, lxterm, uxterm и terminator), хотя, похоже, не все поддерживают колесо горизонтальной прокрутки. - person Nominal Animal; 05.12.2018